Initial commit of firmware
This commit is contained in:
661
Libs/platform/service/clock_manager/inc/sl_clock_manager.h
Normal file
661
Libs/platform/service/clock_manager/inc/sl_clock_manager.h
Normal file
@@ -0,0 +1,661 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief Clock Manager APIs.
|
||||
*******************************************************************************
|
||||
* # License
|
||||
* <b>Copyright 2023 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_CLOCK_MANAGER_H
|
||||
#define SL_CLOCK_MANAGER_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include "sl_status.h"
|
||||
#include "sl_enum.h"
|
||||
#include "sl_device_clock.h"
|
||||
#include "sl_code_classification.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/***************************************************************************//**
|
||||
* @addtogroup clock_manager Clock Manager
|
||||
*
|
||||
* @details
|
||||
* ## Overview
|
||||
*
|
||||
* Clock Manager is a platform-level software module that manages
|
||||
* the device's oscillators and clock tree.
|
||||
* The Clock Manager module is split into two main parts: The Initialization part
|
||||
* and the Runtime part. The runtime part has its component
|
||||
* \a clock_manager_runtime and can be used independently from the initialization
|
||||
* part. The \a clock_manager component includes both the initialization part and the
|
||||
* runtime part and it should be the component added to your project slcp file.
|
||||
*
|
||||
* ## Initialization
|
||||
* The initialization part includes the configuration files
|
||||
* \a sl_clock_manager_oscillator_config.h and \a sl_clock_manager_tree_config.h.
|
||||
* As their name indicates, those C header files are used to configure the different
|
||||
* device oscillators and the device clock tree. Those header files use the CMSIS
|
||||
* Configuration Wizard Annotations and are specific to each device.
|
||||
* The API function sl_clock_manager_init() is used to initialize the Clock Manager
|
||||
* module based on the configuration values specified in the two configuration files.
|
||||
* This function must be called early during your initialization sequence.
|
||||
* If the SL System component (@ref system) is used by your application, the
|
||||
* sl_clock_manager_init() call will be added automatically to your initialization
|
||||
* sequence.
|
||||
*
|
||||
* ### Oscillators Configuration
|
||||
* Oscillators' configurations are all grouped in the \a sl_clock_manager_oscillator_config.h
|
||||
* file. Crystal-based oscillators, HFXO and LFXO, have an enable/disable configuration to
|
||||
* indicate if the required crystal is present or not. In the absence of the required
|
||||
* crystal, the configuration must be disabled and the associated oscillator will
|
||||
* not be initialized.
|
||||
*
|
||||
* The HFXO configuration also provides the configuration for the Crystal Sharing
|
||||
* feature when supported by the device. This feature allows to use the dedicated
|
||||
* HFCLKOUT pin to output a sinusoidal clock that can be used as the HFXO
|
||||
* input for another EFR device. In the configuration, you need to specify if your
|
||||
* device is the leader or the follower. The leader will be the one outputting the
|
||||
* clock and the follower, the one receiving the clock signal. In the leader configuration,
|
||||
* the GPIO pin is used to receive the request from the follower. You can refer to your
|
||||
* device datasheet to know the available location for the HFXO BUFOUT_REQ pin.
|
||||
* In the follower mode, the pin configuration can be used to send an HFXO request
|
||||
* signal to the leader. The "High Frequency Clock Ouput" section of your device
|
||||
* reference manual also provides more details about this feature.
|
||||
*
|
||||
* The first HFRCO module, whose output clock is called HFRCODPLL, can be connected to
|
||||
* the DPLL module to have a better precision clock. When the DPLL is enabled through
|
||||
* the configuration define \a SL_CLOCK_MANAGER_HFRCO_DPLL_EN, the DPLL settings
|
||||
* take precedence over the HFRCO band configuration.
|
||||
*
|
||||
* ### Clock Tree Configuration
|
||||
* The device clock tree configurations are all grouped in the
|
||||
* \a sl_clock_manager_tree_config.h file. Refer to your device's reference manual for
|
||||
* the clock tree diagram and see which peripherals are connected to which clock branches.
|
||||
* In the configuration file, each clock branch can be independently configured.
|
||||
* However, to facilitate the clock setup for users, two additional configurations
|
||||
* were added: \a SL_CLOCK_MANAGER_DEFAULT_HF_CLOCK_SOURCE and
|
||||
* \a SL_CLOCK_MANAGER_DEFAULT_LF_CLOCK_SOURCE. Those configurations allow the selection
|
||||
* of the default high-frequency and low-frequency oscillators to be used inside the clock
|
||||
* tree. Every clock branch that can benefit from those default selections will use them
|
||||
* by default.
|
||||
* On certain devices, the @ref power_manager module offers an Execution Modes feature
|
||||
* with the \a SL_POWER_MANAGER_EXECUTION_MODES_FEATURE_EN configuration. When this feature
|
||||
* is enabled, the \a SL_CLOCK_MANAGER_SYSCLK_SOURCE configuration could be overriden by the
|
||||
* Execution Modes feature. Refer to the description of \a SL_CLOCK_MANAGER_SYSCLK_SOURCE in
|
||||
* \a sl_clock_manager_tree_config.h file to know if this is the case.
|
||||
*
|
||||
* Some peripherals have an internal clock divider. Those are not handled by the
|
||||
* Clock Manager configuration. The peripheral driver will usually expose the divider
|
||||
* configuration when such a divider is present inside the peripheral module.
|
||||
*
|
||||
* The Clock tree configuration is available at compile-time only. The Clock Manager
|
||||
* module does not offer API functions to manipulate the clock tree at runtime.
|
||||
*
|
||||
* The more oscillators are used by different clock branches the more power
|
||||
* consumption you will have. To limit your power consumption, you can try to limit the
|
||||
* number of oscillators used. So for example, only use one High-frequency oscillator
|
||||
* and one Low-frequency oscillator across the clock tree. However, if the
|
||||
* application is radio-based, the HFXO oscillator is mandatory for the Radio
|
||||
* clock branch and if the Radio clock branch is connected to the SYSCLK branch,
|
||||
* this will limit you to use HFXO for SYSCLK as well. In this specific case, SYSCLK
|
||||
* could also be configured to use HFRCO with DPLL, but the chosen frequency must be two
|
||||
* times the HFXO frequency so that the Radio module can retrieve the HF crystal frequency
|
||||
* with its divider. This will also come with an increase in power consumption since both
|
||||
* HFXO and HFRCO oscillators will be used. Refer to your device reference manual to know
|
||||
* if your Radio clock is connected to the SYSCLK clock branch or not.
|
||||
*
|
||||
* @note The Clock Manager Initialization is incompatible with the \a device_init_clocks
|
||||
* (@ref device_init_clocks), \a device_init_hfxo (@ref device_init_hfxo),
|
||||
* \a device_init_hfrco (@ref device_init_hfrco) \a device_init_dpll (@ref device_init_dpll),
|
||||
* \a device_init_rffpll (@ref device_init_rffpll), \a device_init_usbpll (@ref device_init_usbpll),
|
||||
* \a device_init_lfxo (@ref device_init_lfxo) and \a device_init_lfrco (@ref device_init_lfrco)
|
||||
* components.
|
||||
* This does not mean that the \a device_init component (@ref device_init) is incompatible with the
|
||||
* \a clock_manager component. The \a device_init component can pull other initialization
|
||||
* modules like EMU and DCDC that are not related to clocks. Therefore, both
|
||||
* \a device_init and \a clock_manager should be present in your project file. SLC will
|
||||
* take care of pulling only the sub \a device_init_xxx components that are needed.
|
||||
*
|
||||
* The runtime part, which is associated with the \a clock_manager_runtime component,
|
||||
* has also an initialization function of its own, sl_clock_manager_runtime_init().
|
||||
* This function must also be part of the initialization sequence. If the SL System
|
||||
* component (@ref system) is used by your application, the
|
||||
* sl_clock_manager_runtime_init() call will be added automatically to your
|
||||
* initialization sequence.
|
||||
*
|
||||
* ## Functionalities
|
||||
* The Runtime part includes functionalities related to oscillators, clock tree
|
||||
* and the CMU hardware module features. The main functionalities are:
|
||||
* - Retrieving the frequency or precision of an oscillator or clock branch
|
||||
* - Enabling/Disabling modules' bus clock
|
||||
* - Retrieving or setting calibration values for oscillators
|
||||
* - Exporting clocks to GPIO
|
||||
* - Starting an RCO Calibration process based on a reference clock source
|
||||
*
|
||||
* ### Retrieve the frequency or precision of an oscillator or clock branch
|
||||
* API functions sl_clock_manager_get_oscillator_frequency() and
|
||||
* sl_clock_manager_get_oscillator_precision() allow retrieving respectively
|
||||
* the frequency and precision of a given oscillator. Similar functions
|
||||
* exist for clock branches: sl_clock_manager_get_clock_branch_frequency() and
|
||||
* sl_clock_manager_get_clock_branch_precision().
|
||||
*
|
||||
* To retrieve the frequency or precision of a specific peripheral, you will
|
||||
* first need to retrieve to which clock branch this peripheral is connected.
|
||||
* To do so, the Device Manager and its @ref device_peripheral
|
||||
* can be used. The below code example shows how to retrieve the clock branch
|
||||
* of the TIMER0 peripheral.
|
||||
*
|
||||
* @code{.c}
|
||||
* #include "sl_clock_manager.h"
|
||||
* #include "sl_device_peripheral.h"
|
||||
*
|
||||
* sl_status_t status;
|
||||
* uint32_t freq;
|
||||
* sl_clock_branch_t clock_branch;
|
||||
*
|
||||
* clock_branch = sl_device_peripheral_get_clock_branch(SL_PERIPHERAL_TIMER0);
|
||||
* status = sl_clock_manager_get_clock_branch_frequency(clock_branch, &freq);
|
||||
* @endcode
|
||||
*
|
||||
* ### Enable/Disable modules' bus clock
|
||||
* Before accessing a peripheral's register interface, its bus clock must be enabled,
|
||||
* or else a bus fault exception will be triggered. API functions
|
||||
* sl_clock_manager_enable_bus_clock() and sl_clock_manager_disable_bus_clock()
|
||||
* allow to perform such operations.
|
||||
*
|
||||
* Note that the peripheral clock will automatically be enabled when a peripheral
|
||||
* is enabled with the clock on-demand feature.
|
||||
*
|
||||
* ### Oscillator Calibration
|
||||
* The Clock Manager initialization, if present, will calibrate the different
|
||||
* oscillators during the initialization sequence, but sometimes calibration
|
||||
* values must be updated during runtime in certain conditions, for example, if
|
||||
* the device temperature changes too much. This is considered an advanced
|
||||
* functionality and users must be careful as to when to use this functionality.
|
||||
*
|
||||
* API functions sl_clock_manager_set_rc_oscillator_calibration() and
|
||||
* sl_clock_manager_get_rc_oscillator_calibration() allow to set or get the
|
||||
* CAL register of HFRCO and LFRCO oscillators. Not all devices have an LFRCO
|
||||
* module with a CAL register. Some LFRCO modules will have a high-precision
|
||||
* configuration allowing to use the HFXO to auto-calibrate the LFRCO. Refer
|
||||
* to your device reference manual to retrieve oscillator specifications.
|
||||
*
|
||||
* API functions sl_clock_manager_set_hfxo_calibration() and
|
||||
* sl_clock_manager_get_hfxo_calibration() allow to set or get the \a COREBIASANA
|
||||
* inside the HFXO \a XTALCTRL register. The HFXO module has a Core Bias Optimization
|
||||
* stage at the end of the oscillator startup sequence that allows to further
|
||||
* optimize current consumption. This optimization will automatically set the
|
||||
* \a COREBIASANA bitfield when finished. Upon reset, this optimization will run
|
||||
* the first time HFXO is started and afterwards, the \a XTALCTRL->SKIPCOREBIASOPT
|
||||
* bit will automatically be set so that next time HFXO is started during the
|
||||
* application lifetime, the optimization stage will be skipped. This optimization
|
||||
* stage takes a while to run, in the order of hundreds of milliseconds, therefore
|
||||
* we don't want it to run each time HFXO is started.
|
||||
* With the function sl_clock_manager_set_hfxo_calibration() it is possible to
|
||||
* manually set the \a COREBIASANA bitfield and set the \a SKIPCOREBIASOPT bit.
|
||||
* This function will usually be used in the context of an EM4 wake-up where to
|
||||
* save on the initialization sequence time, we want to skip the Core Bias Optimization
|
||||
* stage and manually set the value that would have previously been retrieved with
|
||||
* sl_clock_manager_get_hfxo_calibration() and saved in an EM4 retained memory.
|
||||
* In this context, sl_clock_manager_set_hfxo_calibration() will need to be called
|
||||
* early in the initialization sequence, before the usual clock initialization
|
||||
* function.
|
||||
*
|
||||
* slx_clock_manager_hfxo_set_ctune(), slx_clock_manager_hfxo_get_ctune() and
|
||||
* slx_clock_manager_hfxo_calibrate_ctune() functions allow to manipulate the
|
||||
* HFXO tuning capacitances. Changing the CTUNE value while HFXO is running
|
||||
* can result in significant clock glitches for one clock period. Therefore,
|
||||
* those functions should be used with caution. The difference between the
|
||||
* slx_clock_manager_hfxo_set_ctune() and slx_clock_manager_hfxo_calibrate_ctune()
|
||||
* functions is that the calibration one will also start and wait for the HFXO
|
||||
* Core Bias Optimization stage to complete.
|
||||
*
|
||||
* API functions sl_clock_manager_set_lfxo_calibration() and
|
||||
* sl_clock_manager_get_lfxo_calibration() allow to set and get the LFXO CTUNE
|
||||
* value.
|
||||
*
|
||||
* ### Export clocks to GPIO
|
||||
* The CMU module offers the functionality to export a given clock source to a
|
||||
* GPIO pin. Refer to function sl_clock_manager_set_gpio_clock_output() for more
|
||||
* details and the #sl_clock_manager_export_clock_source_t enum for a list of
|
||||
* acceptable clock sources. Note that there is a specific clock branch named
|
||||
* EXPCLK that is usually connected to the SYSCLK and offers an additional divider.
|
||||
*
|
||||
* ### RCO Calibration
|
||||
* The CMU module also offers RCO Calibration hardware support. This can be
|
||||
* used to calibrate at runtime HFRCO and LFRCO oscillators using a high-precision
|
||||
* reference clock. Refer to your device reference manual for more
|
||||
* details about this functionality. API function
|
||||
* sl_clock_manager_configure_rco_calibration() can be used to configure the
|
||||
* calibration process. Then sl_clock_manager_start_rco_calibration() and
|
||||
* sl_clock_manager_stop_rco_calibration() can be called to start/stop the
|
||||
* process. sl_clock_manager_wait_rco_calibration() function can be called to
|
||||
* actively wait for the process to finish. And finally,
|
||||
* sl_clock_manager_get_rco_calibration_count() can be called to retrieve the
|
||||
* calibration process result.
|
||||
*
|
||||
* @{
|
||||
******************************************************************************/
|
||||
|
||||
/// Export clock source.
|
||||
/// This is to be used with the sl_clock_manager_set_gpio_clock_output() API function.
|
||||
SL_ENUM(sl_clock_manager_export_clock_source_t) {
|
||||
SL_CLOCK_MANAGER_EXPORT_CLOCK_SOURCE_DISABLED, ///< Export Clock Source Disabled
|
||||
SL_CLOCK_MANAGER_EXPORT_CLOCK_SOURCE_FSRCO, ///< Export Clock Source FSRCO
|
||||
SL_CLOCK_MANAGER_EXPORT_CLOCK_SOURCE_HFXO, ///< Export Clock Source HFXO
|
||||
SL_CLOCK_MANAGER_EXPORT_CLOCK_SOURCE_HFRCODPLL, ///< Export Clock Source HFRCODPLL
|
||||
SL_CLOCK_MANAGER_EXPORT_CLOCK_SOURCE_HFRCOEM23, ///< Export Clock Source HFRCOEM23
|
||||
SL_CLOCK_MANAGER_EXPORT_CLOCK_SOURCE_HFEXPCLK, ///< Export Clock Source HFEXPCLK
|
||||
SL_CLOCK_MANAGER_EXPORT_CLOCK_SOURCE_LFXO, ///< Export Clock Source LFXO
|
||||
SL_CLOCK_MANAGER_EXPORT_CLOCK_SOURCE_PLFRCO, ///< Export Clock Source PLFRCO
|
||||
SL_CLOCK_MANAGER_EXPORT_CLOCK_SOURCE_LFRCO, ///< Export Clock Source LFRCO
|
||||
SL_CLOCK_MANAGER_EXPORT_CLOCK_SOURCE_ULFRCO, ///< Export Clock Source ULFRCO
|
||||
SL_CLOCK_MANAGER_EXPORT_CLOCK_SOURCE_HCLK, ///< Export Clock Source HCLK
|
||||
};
|
||||
|
||||
/// Export clock output selection.
|
||||
/// This is to be used with the sl_clock_manager_set_gpio_clock_output() API function.
|
||||
SL_ENUM(sl_clock_manager_export_clock_output_select_t) {
|
||||
SL_CLOCK_MANAGER_EXPORT_CLOCK_OUTPUT_SELECT_0 = 0, ///< Export Clock Output #0
|
||||
SL_CLOCK_MANAGER_EXPORT_CLOCK_OUTPUT_SELECT_1, ///< Export Clock Output #1
|
||||
SL_CLOCK_MANAGER_EXPORT_CLOCK_OUTPUT_SELECT_2, ///< Export Clock Output #2
|
||||
};
|
||||
|
||||
/// Clocks available for Calibration.
|
||||
/// This is to be used with the sl_clock_manager_configure_rco_calibration() API function.
|
||||
SL_ENUM(sl_clock_manager_clock_calibration_t) {
|
||||
SL_CLOCK_MANAGER_CLOCK_CALIBRATION_HCLK, ///< Clock Calibration HCLK
|
||||
SL_CLOCK_MANAGER_CLOCK_CALIBRATION_PRS, ///< Clock Calibration PRS
|
||||
SL_CLOCK_MANAGER_CLOCK_CALIBRATION_HFXO, ///< Clock Calibration HFXO
|
||||
SL_CLOCK_MANAGER_CLOCK_CALIBRATION_LFXO, ///< Clock Calibration LFXO
|
||||
SL_CLOCK_MANAGER_CLOCK_CALIBRATION_HFRCODPLL, ///< Clock Calibration HFRCODPLL
|
||||
SL_CLOCK_MANAGER_CLOCK_CALIBRATION_HFRCOEM23, ///< Clock Calibration HFRCOEM23
|
||||
SL_CLOCK_MANAGER_CLOCK_CALIBRATION_FSRCO, ///< Clock Calibration FSRCO
|
||||
SL_CLOCK_MANAGER_CLOCK_CALIBRATION_LFRCO, ///< Clock Calibration LFRCO
|
||||
SL_CLOCK_MANAGER_CLOCK_CALIBRATION_ULFRCO ///< Clock Calibration ULFRCO
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Prototypes
|
||||
|
||||
/***************************************************************************//**
|
||||
* Performs Clock Manager runtime initialization.
|
||||
*
|
||||
* @return Status code.
|
||||
* SL_STATUS_OK if successful. Error code otherwise.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_clock_manager_runtime_init(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets frequency of given oscillator.
|
||||
*
|
||||
* @param[in] oscillator Oscillator
|
||||
*
|
||||
* @param[out] frequency Oscillator's frequency in Hertz
|
||||
*
|
||||
* @return Status code.
|
||||
* SL_STATUS_OK if successful. Error code otherwise.
|
||||
******************************************************************************/
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_CLOCK_MANAGER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
sl_status_t sl_clock_manager_get_oscillator_frequency(sl_oscillator_t oscillator,
|
||||
uint32_t *frequency);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets precision of given oscillator.
|
||||
*
|
||||
* @param[in] oscillator Oscillator
|
||||
*
|
||||
* @param[out] precision Oscillator's precision in PPM
|
||||
*
|
||||
* @return Status code.
|
||||
* SL_STATUS_OK if successful. Error code otherwise.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_clock_manager_get_oscillator_precision(sl_oscillator_t oscillator,
|
||||
uint16_t *precision);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets frequency of given clock branch.
|
||||
*
|
||||
* @param[in] clock_branch Clock Branch
|
||||
*
|
||||
* @param[out] frequency Clock Branch's frequency in Hertz
|
||||
*
|
||||
* @return Status code.
|
||||
* SL_STATUS_OK if successful. Error code otherwise.
|
||||
******************************************************************************/
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_CLOCK_MANAGER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
sl_status_t sl_clock_manager_get_clock_branch_frequency(sl_clock_branch_t clock_branch,
|
||||
uint32_t *frequency);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets precision of given clock branch.
|
||||
*
|
||||
* @param[in] clock_branch Clock Branch
|
||||
*
|
||||
* @param[out] precision Clock Branch's precision in PPM
|
||||
*
|
||||
* @return Status code.
|
||||
* SL_STATUS_OK if successful. Error code otherwise.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_clock_manager_get_clock_branch_precision(sl_clock_branch_t clock_branch,
|
||||
uint16_t *precision);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Enables the given module's bus clock.
|
||||
*
|
||||
* @param[in] module_bus_clock module's bus clock to enable.
|
||||
*
|
||||
* @return Status code.
|
||||
* SL_STATUS_OK if successful. Error code otherwise.
|
||||
*
|
||||
* @note modules' bus clocks are defined in the
|
||||
* @ref device_clock in the Bus Clock Defines section.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_clock_manager_enable_bus_clock(sl_bus_clock_t module_bus_clock);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Disables the given module's bus clock.
|
||||
*
|
||||
* @param[in] module_bus_clock module's bus clock to disable.
|
||||
*
|
||||
* @return Status code.
|
||||
* SL_STATUS_OK if successful. Error code otherwise.
|
||||
*
|
||||
* @note modules' bus clocks are defined in the
|
||||
* @ref device_clock in the Bus Clock Defines section.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_clock_manager_disable_bus_clock(sl_bus_clock_t module_bus_clock);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Configures one clock export output with specified clock source.
|
||||
*
|
||||
* @param[in] export_clock_source One of the exportable clock source.
|
||||
*
|
||||
* @param[in] output_select Selected export clock output channel.
|
||||
*
|
||||
* @param[in] hfexp_divider HFEXP clock divider (1 to 32).
|
||||
* Note: This parameter only affects the EXPCLK
|
||||
* branch frequency.
|
||||
*
|
||||
* @param[in] port GPIO port to output exported clock.
|
||||
*
|
||||
* @param[in] pin GPIO pin number to output exported clock.
|
||||
*
|
||||
* @return Status code.
|
||||
* SL_STATUS_OK if successful. Error code otherwise.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_clock_manager_set_gpio_clock_output(sl_clock_manager_export_clock_source_t export_clock_source,
|
||||
sl_clock_manager_export_clock_output_select_t output_select,
|
||||
uint16_t hfexp_divider,
|
||||
uint32_t port,
|
||||
uint32_t pin);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Sets the RC oscillator frequency tuning control.
|
||||
*
|
||||
* @param[in] oscillator RC Oscillator to set tuning value for.
|
||||
*
|
||||
* @param[in] val The RC oscillator frequency tuning setting to use.
|
||||
*
|
||||
* @return Status code.
|
||||
* SL_STATUS_OK if successful. Error code otherwise.
|
||||
*
|
||||
* @note RC Oscillator tuning is done during production, and the tuning value is
|
||||
* loaded after a reset by the Clock Manager initialization code.
|
||||
* Changing the tuning value from the calibrated value is for more advanced
|
||||
* use. Certain oscillators also have build-in tuning optimization.
|
||||
*
|
||||
* @note Supported RC oscillators include:
|
||||
* - SL_OSCILLATOR_HFRCODPLL
|
||||
* - SL_OSCILLATOR_HFRCOEM23
|
||||
* - SL_OSCILLATOR_LFRCO
|
||||
******************************************************************************/
|
||||
sl_status_t sl_clock_manager_set_rc_oscillator_calibration(sl_oscillator_t oscillator,
|
||||
uint32_t val);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets the RC oscillator frequency tuning setting.
|
||||
*
|
||||
* @param[in] oscillator An RC oscillator to get tuning value for.
|
||||
*
|
||||
* @param[out] val The RC oscillator frequency tuning setting in use.
|
||||
*
|
||||
* @return Status code.
|
||||
* SL_STATUS_OK if successful. Error code otherwise.
|
||||
*
|
||||
* @note Supported RC oscillators include:
|
||||
* - SL_OSCILLATOR_HFRCODPLL
|
||||
* - SL_OSCILLATOR_HFRCOEM23
|
||||
* - SL_OSCILLATOR_LFRCO
|
||||
******************************************************************************/
|
||||
sl_status_t sl_clock_manager_get_rc_oscillator_calibration(sl_oscillator_t oscillator,
|
||||
uint32_t *val);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Sets the HFXO calibration value.
|
||||
*
|
||||
* @param[in] val
|
||||
* The HFXO calibration setting to use.
|
||||
*
|
||||
* @return Status code.
|
||||
* SL_STATUS_OK if successful. Error code otherwise.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_clock_manager_set_hfxo_calibration(uint32_t val);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets the HFXO calibration value.
|
||||
*
|
||||
* @param[out] val The current HFXO calibration value.
|
||||
*
|
||||
* @return Status code.
|
||||
* SL_STATUS_OK if successful. Error code otherwise.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_clock_manager_get_hfxo_calibration(uint32_t *val);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Sets the HFXO's CTUNE.
|
||||
*
|
||||
* @param[in] ctune The HFXO's CTUNE value.
|
||||
*
|
||||
* @return Status code.
|
||||
* SL_STATUS_OK if successful. Error code otherwise.
|
||||
*
|
||||
* @note Sets the XI value to the given ctune value and sets the XO value based
|
||||
* on that same value, but with an offset that is hardware dependent.
|
||||
* Updating CTune while the crystal oscillator is running can
|
||||
* result in significant clock glitches for one XO clock period.
|
||||
* Should be used with caution.
|
||||
******************************************************************************/
|
||||
sl_status_t slx_clock_manager_hfxo_set_ctune(uint32_t ctune);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets the HFXO's CTUNE.
|
||||
*
|
||||
* @param[out] ctune The returned HFXO's CTUNE value.
|
||||
*
|
||||
* @return Status code.
|
||||
* SL_STATUS_OK if successful. Error code otherwise.
|
||||
*
|
||||
* @note This function only returns the CTUNE XI value.
|
||||
* The XO value follows the XI value with a fixed delta that is
|
||||
* hardware dependent.
|
||||
******************************************************************************/
|
||||
sl_status_t slx_clock_manager_hfxo_get_ctune(uint32_t *ctune);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Updates the tuning capacitances and calibrate the Core Bias Current.
|
||||
*
|
||||
* @param[in] ctune The HFXO's CTUNE value.
|
||||
*
|
||||
* @return Status code.
|
||||
* SL_STATUS_OK if successful. Error code otherwise.
|
||||
*
|
||||
* @note Calibrating the CTUNE is time consuming and will cause glitches on the
|
||||
* HFXO's clock. Care and caution should be taken when using this API.
|
||||
******************************************************************************/
|
||||
sl_status_t slx_clock_manager_hfxo_calibrate_ctune(uint32_t ctune);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Sets the LFXO frequency tuning control.
|
||||
*
|
||||
* @param[in] val The LFXO frequency tuning setting to use.
|
||||
*
|
||||
* @return Status code.
|
||||
* SL_STATUS_OK if successful. Error code otherwise.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_clock_manager_set_lfxo_calibration(uint32_t val);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets the LFXO frequency tuning setting.
|
||||
*
|
||||
* @param[out] val The LFXO frequency tuning setting to use.
|
||||
*
|
||||
* @return Status code.
|
||||
* SL_STATUS_OK if successful. Error code otherwise.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_clock_manager_get_lfxo_calibration(uint32_t *val);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Configures the RCO calibration.
|
||||
*
|
||||
* @param[in] cycles Number of cycles to run calibration. Increasing this
|
||||
* number increases precision, but the calibration will
|
||||
* take more time.
|
||||
*
|
||||
* @param[in] down_counter_selection
|
||||
* The clock which will be counted down cycles.
|
||||
*
|
||||
* @param[in] up_counter_selection
|
||||
* The number of cycles generated by this clock will be counted and
|
||||
* added up, the result can be given with
|
||||
* sl_clock_manager_get_rco_calibration_count().
|
||||
*
|
||||
* @param[in] continuous_calibration
|
||||
* Flag when true configures continuous calibration.
|
||||
*
|
||||
* @return Status code.
|
||||
* SL_STATUS_OK if successful. Error code otherwise.
|
||||
*
|
||||
* @note RCO calibration related functions are not thread-safe and should
|
||||
* therefore not be called across multiple tasks.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_clock_manager_configure_rco_calibration(uint32_t cycles,
|
||||
sl_clock_manager_clock_calibration_t down_counter_selection,
|
||||
sl_clock_manager_clock_calibration_t up_counter_selection,
|
||||
bool continuous_calibration);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Starts the RCO calibration.
|
||||
*
|
||||
* @note RCO calibration related functions are not thread-safe and should
|
||||
* therefore not be called across multiple tasks.
|
||||
******************************************************************************/
|
||||
void sl_clock_manager_start_rco_calibration(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Stops the RCO calibration.
|
||||
*
|
||||
* @note RCO calibration related functions are not thread-safe and should
|
||||
* therefore not be called across multiple tasks.
|
||||
******************************************************************************/
|
||||
void sl_clock_manager_stop_rco_calibration(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Waits for the RCO calibration to finish.
|
||||
*
|
||||
* @note RCO calibration related functions are not thread-safe and should
|
||||
* therefore not be called across multiple tasks.
|
||||
******************************************************************************/
|
||||
void sl_clock_manager_wait_rco_calibration(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets calibration count value, returns the value of the up counter.
|
||||
*
|
||||
* @param[out] count Calibration count value.
|
||||
*
|
||||
* @return Status code.
|
||||
* SL_STATUS_OK if successful. Error code otherwise.
|
||||
*
|
||||
* @note RCO calibration related functions are not thread-safe and should
|
||||
* therefore not be called across multiple tasks.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_clock_manager_get_rco_calibration_count(uint32_t *count);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Waits for USBPLL clock to be ready.
|
||||
*
|
||||
* @return Status code.
|
||||
* SL_STATUS_OK if successful. Error code otherwise.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_clock_manager_wait_usbpll(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* When this callback function is called, it means that HFXO failed twice in
|
||||
* a row to start with normal configurations. This may mean that there is a
|
||||
* bad crystal. When getting this callback, HFXO is running but its properties
|
||||
* (frequency, precision) are not guaranteed. This should be considered as an
|
||||
* error situation.
|
||||
*
|
||||
* @note This callback will be called only when the
|
||||
* SL_CLOCK_MANAGER_HFXO_SLEEPY_CRYSTAL_SUPPORT config is enabled
|
||||
******************************************************************************/
|
||||
void sl_clock_manager_hfxo_notify_consecutive_failed_startups(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Sets the external FLASH reference clock.
|
||||
*
|
||||
* @param[in] oscillator Oscillator used to clock the external FLASH.
|
||||
*
|
||||
* @return Status code.
|
||||
* SL_STATUS_OK if successful. Error code otherwise.
|
||||
*
|
||||
* @note This API is not thread-safe and should therefore not be called
|
||||
* across multiple tasks.
|
||||
******************************************************************************/
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_CLOCK_MANAGER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
sl_status_t sl_clock_manager_set_ext_flash_clk(sl_oscillator_t oscillator);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets the external FLASH clock source.
|
||||
*
|
||||
* @param[out] oscillator Oscillator used to clock the external FLASH.
|
||||
*
|
||||
* @return Status code.
|
||||
* SL_STATUS_OK if successful. Error code otherwise.
|
||||
******************************************************************************/
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_CLOCK_MANAGER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
sl_status_t sl_clock_manager_get_ext_flash_clk(sl_oscillator_t *oscillator);
|
||||
|
||||
/** @} (end addtogroup clock_manager) */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // SL_CLOCK_MANAGER_H
|
||||
@@ -0,0 +1,62 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief Clock Manager Init APIs.
|
||||
*******************************************************************************
|
||||
* # License
|
||||
* <b>Copyright 2023 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_CLOCK_MANAGER_INIT_H
|
||||
#define SL_CLOCK_MANAGER_INIT_H
|
||||
|
||||
#include "sl_status.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/***************************************************************************//**
|
||||
* @addtogroup clock_manager Clock Manager
|
||||
* @{
|
||||
******************************************************************************/
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Prototypes
|
||||
|
||||
/***************************************************************************//**
|
||||
* Initializes Oscillators and Clock branches.
|
||||
*
|
||||
* @return Status code.
|
||||
* SL_STATUS_OK if successful. Error code otherwise.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_clock_manager_init(void);
|
||||
|
||||
/** @} (end addtogroup clock_manager) */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // SL_CLOCK_MANAGER_INIT_H
|
||||
64
Libs/platform/service/clock_manager/inc/sli_clock_manager.h
Normal file
64
Libs/platform/service/clock_manager/inc/sli_clock_manager.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief Clock Manager Private API definition.
|
||||
*******************************************************************************
|
||||
* # License
|
||||
* <b>Copyright 2023 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_CLOCK_MANAGER_H
|
||||
#define SLI_CLOCK_MANAGER_H
|
||||
|
||||
#include "sl_clock_manager.h"
|
||||
#include "sl_status.h"
|
||||
#include "sl_compiler.h"
|
||||
#include "sl_code_classification.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/***************************************************************************//**
|
||||
* Set SYSCLK clock source.
|
||||
******************************************************************************/
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_CLOCK_MANAGER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
sl_status_t sli_clock_manager_set_sysclk_source(sl_oscillator_t source);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Get SYSCLK clock source.
|
||||
******************************************************************************/
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_CLOCK_MANAGER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
sl_status_t sli_clock_manager_get_sysclk_source(sl_oscillator_t *source);
|
||||
|
||||
/***************************************************************************//**
|
||||
* When this callback function is called, it means that HFXO is ready.
|
||||
******************************************************************************/
|
||||
__WEAK void sli_clock_manager_notify_hfxo_ready(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // SLI_CLOCK_MANAGER_H
|
||||
313
Libs/platform/service/clock_manager/src/sl_clock_manager.c
Normal file
313
Libs/platform/service/clock_manager/src/sl_clock_manager.c
Normal file
@@ -0,0 +1,313 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief Clock Manager API implementations.
|
||||
*******************************************************************************
|
||||
* # License
|
||||
* <b>Copyright 2023 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 "sli_clock_manager.h"
|
||||
#include "sl_clock_manager.h"
|
||||
#include "sli_clock_manager.h"
|
||||
#include "sli_clock_manager_hal.h"
|
||||
#include "sl_assert.h"
|
||||
#include "cmsis_compiler.h"
|
||||
|
||||
/***************************************************************************//**
|
||||
* Performs Clock Manager runtime initialization.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_clock_manager_runtime_init(void)
|
||||
{
|
||||
return sli_clock_manager_hal_runtime_init();
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets frequency of given oscillator.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_clock_manager_get_oscillator_frequency(sl_oscillator_t oscillator,
|
||||
uint32_t *frequency)
|
||||
{
|
||||
if (frequency == NULL) {
|
||||
return SL_STATUS_NULL_POINTER;
|
||||
}
|
||||
|
||||
return sli_clock_manager_hal_get_oscillator_frequency(oscillator, frequency);
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets precision of given oscillator.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_clock_manager_get_oscillator_precision(sl_oscillator_t oscillator,
|
||||
uint16_t *precision)
|
||||
{
|
||||
if (precision == NULL) {
|
||||
return SL_STATUS_NULL_POINTER;
|
||||
}
|
||||
|
||||
return sli_clock_manager_hal_get_oscillator_precision(oscillator, precision);
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets frequency of given clock branch.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_clock_manager_get_clock_branch_frequency(sl_clock_branch_t clock_branch,
|
||||
uint32_t *frequency)
|
||||
{
|
||||
if (frequency == NULL) {
|
||||
return SL_STATUS_NULL_POINTER;
|
||||
}
|
||||
|
||||
return sli_clock_manager_hal_get_clock_branch_frequency(clock_branch, frequency);
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets precision of given clock branch.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_clock_manager_get_clock_branch_precision(sl_clock_branch_t clock_branch,
|
||||
uint16_t *precision)
|
||||
{
|
||||
if (precision == NULL) {
|
||||
return SL_STATUS_NULL_POINTER;
|
||||
}
|
||||
|
||||
return sli_clock_manager_hal_get_clock_branch_precision(clock_branch, precision);
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Enables the given module's bus clock.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_clock_manager_enable_bus_clock(sl_bus_clock_t module_bus_clock)
|
||||
{
|
||||
return sli_clock_manager_hal_enable_bus_clock(module_bus_clock, true);
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Disables the given module's bus clock.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_clock_manager_disable_bus_clock(sl_bus_clock_t module_bus_clock)
|
||||
{
|
||||
return sli_clock_manager_hal_enable_bus_clock(module_bus_clock, false);
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Configures one clock export output with specified clock source.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_clock_manager_set_gpio_clock_output(sl_clock_manager_export_clock_source_t export_clock_source,
|
||||
sl_clock_manager_export_clock_output_select_t output_select,
|
||||
uint16_t hfexp_divider,
|
||||
uint32_t port,
|
||||
uint32_t pin)
|
||||
{
|
||||
return sli_clock_manager_hal_set_gpio_clock_output(export_clock_source, output_select, hfexp_divider, port, pin);
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Sets the RC oscillator frequency tuning control.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_clock_manager_set_rc_oscillator_calibration(sl_oscillator_t oscillator,
|
||||
uint32_t val)
|
||||
{
|
||||
return sli_clock_manager_hal_set_rc_oscillator_calibration(oscillator, val);
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets the RC oscillator frequency tuning setting.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_clock_manager_get_rc_oscillator_calibration(sl_oscillator_t oscillator,
|
||||
uint32_t *val)
|
||||
{
|
||||
if (val == NULL) {
|
||||
return SL_STATUS_NULL_POINTER;
|
||||
}
|
||||
return sli_clock_manager_hal_get_rc_oscillator_calibration(oscillator, val);
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Sets the HFXO calibration value.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_clock_manager_set_hfxo_calibration(uint32_t val)
|
||||
{
|
||||
return sli_clock_manager_hal_set_hfxo_calibration(val);
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets the HFXO calibration value.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_clock_manager_get_hfxo_calibration(uint32_t *val)
|
||||
{
|
||||
if (val == NULL) {
|
||||
return SL_STATUS_NULL_POINTER;
|
||||
}
|
||||
return sli_clock_manager_hal_get_hfxo_calibration(val);
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Sets the HFXO CTUNE setting.
|
||||
******************************************************************************/
|
||||
sl_status_t slx_clock_manager_hfxo_set_ctune(uint32_t ctune)
|
||||
{
|
||||
return sli_clock_manager_hal_hfxo_set_ctune(ctune);
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets the HFXO CTUNE setting.
|
||||
******************************************************************************/
|
||||
sl_status_t slx_clock_manager_hfxo_get_ctune(uint32_t *ctune)
|
||||
{
|
||||
if (ctune == NULL) {
|
||||
return SL_STATUS_NULL_POINTER;
|
||||
}
|
||||
return sli_clock_manager_hal_hfxo_get_ctune(ctune);
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Updates the tuning capacitances and calibrate the Core Bias Current.
|
||||
******************************************************************************/
|
||||
sl_status_t slx_clock_manager_hfxo_calibrate_ctune(uint32_t ctune)
|
||||
{
|
||||
return sli_clock_manager_hal_hfxo_calibrate_ctune(ctune);
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Sets the LFXO frequency tuning control.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_clock_manager_set_lfxo_calibration(uint32_t val)
|
||||
{
|
||||
return sli_clock_manager_hal_set_lfxo_calibration(val);
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets the LFXO frequency tuning setting.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_clock_manager_get_lfxo_calibration(uint32_t *val)
|
||||
{
|
||||
if (val == NULL) {
|
||||
return SL_STATUS_NULL_POINTER;
|
||||
}
|
||||
return sli_clock_manager_hal_get_lfxo_calibration(val);
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Configures the RCO calibration.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_clock_manager_configure_rco_calibration(uint32_t cycles,
|
||||
sl_clock_manager_clock_calibration_t down_counter_selection,
|
||||
sl_clock_manager_clock_calibration_t up_counter_selection,
|
||||
bool continuous_calibration)
|
||||
{
|
||||
return sli_clock_manager_hal_configure_rco_calibration(cycles, down_counter_selection, up_counter_selection, continuous_calibration);
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Starts the RCO calibration.
|
||||
******************************************************************************/
|
||||
void sl_clock_manager_start_rco_calibration(void)
|
||||
{
|
||||
sli_clock_manager_hal_start_rco_calibration();
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Stops the RCO calibration.
|
||||
******************************************************************************/
|
||||
void sl_clock_manager_stop_rco_calibration(void)
|
||||
{
|
||||
sli_clock_manager_hal_stop_rco_calibration();
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Waits for the RCO calibration to finish.
|
||||
******************************************************************************/
|
||||
void sl_clock_manager_wait_rco_calibration(void)
|
||||
{
|
||||
sli_clock_manager_hal_wait_rco_calibration();
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets calibration count value.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_clock_manager_get_rco_calibration_count(uint32_t *count)
|
||||
{
|
||||
if (count == NULL) {
|
||||
return SL_STATUS_NULL_POINTER;
|
||||
}
|
||||
|
||||
return sli_clock_manager_hal_get_rco_calibration_count(count);
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Sets SYSCLK clock source.
|
||||
******************************************************************************/
|
||||
sl_status_t sli_clock_manager_set_sysclk_source(sl_oscillator_t source)
|
||||
{
|
||||
return sli_clock_manager_hal_set_sysclk_source(source);
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets SYSCLK clock source.
|
||||
******************************************************************************/
|
||||
sl_status_t sli_clock_manager_get_sysclk_source(sl_oscillator_t *source)
|
||||
{
|
||||
if (source == NULL) {
|
||||
return SL_STATUS_NULL_POINTER;
|
||||
}
|
||||
|
||||
return sli_clock_manager_hal_get_sysclk_source(source);
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Waits for USBPLL clock to be ready.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_clock_manager_wait_usbpll(void)
|
||||
{
|
||||
return sli_clock_manager_hal_wait_usbpll();
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* When this callback function is called, it means that HFXO failed twice in
|
||||
* a row to start with normal configurations. This may mean that there is a
|
||||
* bad crystal. When getting this callback, HFXO is running but its properties
|
||||
* (frequency, precision) are not guaranteed. This should be considered as an
|
||||
* error situation.
|
||||
******************************************************************************/
|
||||
__WEAK void sl_clock_manager_hfxo_notify_consecutive_failed_startups(void)
|
||||
{
|
||||
EFM_ASSERT(false);
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Sets the external FLASH reference clock.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_clock_manager_set_ext_flash_clk(sl_oscillator_t oscillator)
|
||||
{
|
||||
return sli_clock_manager_hal_set_ext_flash_clk(oscillator);
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets the external FLASH clock source.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_clock_manager_get_ext_flash_clk(sl_oscillator_t *oscillator)
|
||||
{
|
||||
return sli_clock_manager_hal_get_ext_flash_clk(oscillator);
|
||||
}
|
||||
1040
Libs/platform/service/clock_manager/src/sl_clock_manager_hal_s2.c
Normal file
1040
Libs/platform/service/clock_manager/src/sl_clock_manager_hal_s2.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,40 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief Clock Manager Init API implementations.
|
||||
*******************************************************************************
|
||||
* # License
|
||||
* <b>Copyright 2023 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_clock_manager_init.h"
|
||||
#include "sli_clock_manager_init_hal.h"
|
||||
|
||||
/***************************************************************************//**
|
||||
* Initializes Oscillators and Clock branches.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_clock_manager_init(void)
|
||||
{
|
||||
return sli_clock_manager_hal_init();
|
||||
}
|
||||
@@ -0,0 +1,886 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief Clock Manager Init HAL API implementations.
|
||||
*******************************************************************************
|
||||
* # License
|
||||
* <b>Copyright 2023 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_clock_manager_oscillator_config.h"
|
||||
#include "sl_clock_manager_tree_config.h"
|
||||
#include "sli_clock_manager_init_hal.h"
|
||||
#include "sl_clock_manager.h"
|
||||
#include "sl_status.h"
|
||||
#include "sl_assert.h"
|
||||
#include "em_device.h"
|
||||
#include "em_cmu.h"
|
||||
#include "sl_gpio.h"
|
||||
|
||||
#if defined(SLI_CLOCK_MANAGER_RUNTIME_CONFIGURATION)
|
||||
#include "sli_clock_manager_runtime_configuration.h"
|
||||
#endif
|
||||
|
||||
#if defined(RFFPLL_PRESENT)
|
||||
#if defined(SL_CLOCK_MANAGER_RFFPLL_BAND) && (SL_CLOCK_MANAGER_RFFPLL_BAND == 7)
|
||||
#ifdef SL_CLOCK_MANAGER_AUTO_BAND_VALID
|
||||
#include "rail_config.h"
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
******************************* DEFINES ***********************************
|
||||
******************************************************************************/
|
||||
|
||||
// Fetch HFXO CTUNE value from USERDATA page as a manufacturing token
|
||||
#define MFG_CTUNE_HFXO_ADDR 0x0FE00100UL
|
||||
#define MFG_CTUNE_HFXO_VAL (*((uint16_t *) (MFG_CTUNE_HFXO_ADDR)))
|
||||
|
||||
// Fetch LFXO CTUNE value from USERDATA page as a manufacturing token
|
||||
#define MFG_CTUNE_LFXO_ADDR 0x0FE0009CUL
|
||||
#define MFG_CTUNE_LFXO_VAL (*((uint8_t *) (MFG_CTUNE_LFXO_ADDR)))
|
||||
|
||||
#if defined(RFFPLL_PRESENT)
|
||||
// If RADIO_CONFIG_RFFPLL_CONFIG_PRESENT is not defined, either there is no
|
||||
// radio configuration in the project or the radio configuration that is
|
||||
// present does not include an RFFPLL configuration.
|
||||
// In either case, the Auto-Band feature cannot work, so fall back to the
|
||||
// default band (Band 9xx).
|
||||
#if defined(SL_CLOCK_MANAGER_RFFPLL_BAND) && (SL_CLOCK_MANAGER_RFFPLL_BAND == 7)
|
||||
#ifndef RADIO_CONFIG_RFFPLL_CONFIG_PRESENT
|
||||
#undef SL_CLOCK_MANAGER_RFFPLL_BAND
|
||||
#define SL_CLOCK_MANAGER_RFFPLL_BAND 6
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Allocated PRS channel for crystal sharing
|
||||
#if defined(_HFXO_CTRL_PRSSTATUSSEL0_MASK)
|
||||
#define HFXO_CRYSTSAL_SHARING_PRS_CHANNEL 0
|
||||
#endif
|
||||
|
||||
#if defined(SLI_CLOCK_MANAGER_RUNTIME_CONFIGURATION)
|
||||
#define FUNCTION_SCOPE
|
||||
#else
|
||||
#define FUNCTION_SCOPE static
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
****************************** TYPEDEFS ***********************************
|
||||
******************************************************************************/
|
||||
|
||||
#if defined(RFFPLL_PRESENT)
|
||||
typedef struct {
|
||||
uint32_t frequency; // Host target frequency.
|
||||
uint8_t divider_y; // Divider Y for digital.
|
||||
uint8_t divider_x; // Divider X for Radio.
|
||||
uint8_t divider_n; // Feedback divider N.
|
||||
} clock_manager_rffpll_config_t;
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
************************** LOCAL VARIABLES ********************************
|
||||
******************************************************************************/
|
||||
|
||||
#if defined(RFFPLL_PRESENT) \
|
||||
&& defined(SL_CLOCK_MANAGER_HFXO_EN) && (SL_CLOCK_MANAGER_HFXO_EN == 1) \
|
||||
&& (SL_CLOCK_MANAGER_RFFPLL_CUSTOM_BAND == 0) \
|
||||
&& !((SL_CLOCK_MANAGER_RFFPLL_BAND == 7) && defined(RADIO_CONFIG_RFFPLL_CONFIG_PRESENT))
|
||||
// Table of possible radio frequency bands and their associated settings.
|
||||
static clock_manager_rffpll_config_t rffpll_band_config_39MHz[] = {
|
||||
{ 97500000, 23, 7, 115 }, // Band 450 MHz
|
||||
{ 98380000, 22, 7, 111 }, // Band 470 MHz
|
||||
{ 97500000, 23, 7, 115 }, // Band 780 MHz
|
||||
{ 97500000, 20, 6, 100 }, // Band 863 MHz
|
||||
{ 97500000, 23, 7, 115 }, // Band 896 MHz
|
||||
{ 96520000, 20, 6, 99 }, // Band 928 MHz
|
||||
{ 97500000, 20, 6, 100 } // Band 9xx MHz (covers from 901 to 928 MHz)
|
||||
};
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
************************** GLOBAL VARIABLES *******************************
|
||||
******************************************************************************/
|
||||
|
||||
#if defined(SLI_CLOCK_MANAGER_RUNTIME_CONFIGURATION)
|
||||
uint32_t SLI_CLOCK_MANAGER_HFXO_MODE = SL_CLOCK_MANAGER_HFXO_MODE;
|
||||
uint32_t SLI_CLOCK_MANAGER_HFXO_CTUNE_FIXED_STEADY = SLI_CLOCK_MANAGER_HFXO_CTUNE_FIXED_STEADY_DEFAULT;
|
||||
uint32_t SLI_CLOCK_MANAGER_HFRCO_BAND = SL_CLOCK_MANAGER_HFRCO_BAND;
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
*************************** LOCAL FUNCTIONS *******************************
|
||||
******************************************************************************/
|
||||
|
||||
#if defined(HFXO_PRESENT) \
|
||||
&& defined(SL_CLOCK_MANAGER_HFXO_EN) && SL_CLOCK_MANAGER_HFXO_EN == 1
|
||||
/***************************************************************************//**
|
||||
* Initializes HFXO Oscillator.
|
||||
******************************************************************************/
|
||||
FUNCTION_SCOPE sl_status_t init_hfxo(void)
|
||||
{
|
||||
CMU_HFXOInit_TypeDef clock_manager_hfxo_init = CMU_HFXOINIT_DEFAULT;
|
||||
clock_manager_hfxo_init.mode = SLI_CLOCK_MANAGER_HFXO_MODE >> _HFXO_CFG_MODE_SHIFT;
|
||||
|
||||
if (SLI_CLOCK_MANAGER_HFXO_MODE == cmuHfxoOscMode_ExternalSine) {
|
||||
clock_manager_hfxo_init = (CMU_HFXOInit_TypeDef)CMU_HFXOINIT_EXTERNAL_SINE;
|
||||
#if defined(_HFXO_CFG_MODE_EXTCLKPKDET)
|
||||
} else if (SLI_CLOCK_MANAGER_HFXO_MODE == cmuHfxoOscMode_ExternalSinePkDet) {
|
||||
clock_manager_hfxo_init = (CMU_HFXOInit_TypeDef)CMU_HFXOINIT_EXTERNAL_SINEPKDET;
|
||||
#endif
|
||||
}
|
||||
|
||||
int ctune = -1;
|
||||
|
||||
#if defined(_DEVINFO_MODXOCAL_HFXOCTUNEXIANA_MASK)
|
||||
// Use HFXO tuning value from DEVINFO if available (PCB modules)
|
||||
if ((DEVINFO->MODULEINFO & _DEVINFO_MODULEINFO_HFXOCALVAL_MASK) == 0) {
|
||||
ctune = DEVINFO->MODXOCAL & _DEVINFO_MODXOCAL_HFXOCTUNEXIANA_MASK;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Use HFXO tuning value from MFG token in UD page if not already set
|
||||
if ((ctune == -1)
|
||||
#if defined(SL_CLOCK_MANAGER_CTUNE_MFG_HFXO_EN)
|
||||
&& (SL_CLOCK_MANAGER_CTUNE_MFG_HFXO_EN == 1)
|
||||
#endif
|
||||
&& (MFG_CTUNE_HFXO_VAL <= (_HFXO_XTALCTRL_CTUNEXIANA_MASK >> _HFXO_XTALCTRL_CTUNEXIANA_SHIFT))) {
|
||||
ctune = MFG_CTUNE_HFXO_VAL;
|
||||
}
|
||||
|
||||
// Use HFXO tuning value from configurations as fallback
|
||||
if (ctune == -1) {
|
||||
ctune = SL_CLOCK_MANAGER_HFXO_CTUNE;
|
||||
}
|
||||
|
||||
// Configure CTUNE XI and XO.
|
||||
if (ctune != -1) {
|
||||
clock_manager_hfxo_init.ctuneXiAna = (uint8_t)ctune;
|
||||
|
||||
// Ensure CTUNE XO plus a delta is within the correct range. The delta accounts for internal chip
|
||||
// load imbalance on some series 2 chips.
|
||||
ctune += CMU_HFXOCTuneDeltaGet();
|
||||
if (ctune < 0) {
|
||||
ctune = 0;
|
||||
} else if (ctune > ((int)(_HFXO_XTALCTRL_CTUNEXOANA_MASK >> _HFXO_XTALCTRL_CTUNEXOANA_SHIFT))) {
|
||||
ctune = (int)(_HFXO_XTALCTRL_CTUNEXOANA_MASK >> _HFXO_XTALCTRL_CTUNEXOANA_SHIFT);
|
||||
}
|
||||
clock_manager_hfxo_init.ctuneXoAna = ctune;
|
||||
}
|
||||
|
||||
#if defined(SLI_CLOCK_MANAGER_RUNTIME_CONFIGURATION)
|
||||
if (SLI_CLOCK_MANAGER_HFXO_CTUNE_FIXED_STEADY != SLI_CLOCK_MANAGER_HFXO_CTUNE_FIXED_STEADY_DEFAULT) {
|
||||
clock_manager_hfxo_init.ctuneFixAna = SLI_CLOCK_MANAGER_HFXO_CTUNE_FIXED_STEADY;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(SL_CLOCK_MANAGER_HFXO_CRYSTAL_SHARING_EN) && (SL_CLOCK_MANAGER_HFXO_CRYSTAL_SHARING_EN == 1)
|
||||
// Set port and pin.
|
||||
GPIO_Port_TypeDef port = SL_CLOCK_MANAGER_HFXO_CRYSTAL_SHARING_GPIO_PORT;
|
||||
unsigned int pin = SL_CLOCK_MANAGER_HFXO_CRYSTAL_SHARING_GPIO_PIN;
|
||||
|
||||
// Enable HFXO and GPIO bus clocks.
|
||||
sl_clock_manager_enable_bus_clock(SL_BUS_CLOCK_HFXO0);
|
||||
sl_clock_manager_enable_bus_clock(SL_BUS_CLOCK_GPIO);
|
||||
#if defined(SL_CLOCK_MANAGER_HFXO_CRYSTAL_SHARING_FOLLOWER_EN) && (SL_CLOCK_MANAGER_HFXO_CRYSTAL_SHARING_FOLLOWER_EN == 1)
|
||||
// Initialize Crystal sharing follower.
|
||||
sl_clock_manager_enable_bus_clock(SL_BUS_CLOCK_PRS);
|
||||
|
||||
EFM_ASSERT(GPIO_PORT_PIN_VALID(port, pin));
|
||||
|
||||
uint32_t mask = 0U, value = 0U;
|
||||
|
||||
bool was_locked = HFXO0->STATUS & HFXO_STATUS_LOCK_LOCKED ? true : false;
|
||||
|
||||
// Unlock register interface.
|
||||
HFXO0->LOCK = HFXO_LOCK_LOCKKEY_UNLOCK;
|
||||
HFXO0->IEN_SET = HFXO_IEN_BUFOUTRDY;
|
||||
|
||||
BUS_RegMaskedWrite(&HFXO0->CTRL, _HFXO_CTRL_PRSSTATUSSEL0_MASK, (_HFXO_CTRL_PRSSTATUSSEL0_ENS << _HFXO_CTRL_PRSSTATUSSEL0_SHIFT));
|
||||
|
||||
if (was_locked) {
|
||||
HFXO0->LOCK = ~HFXO_LOCK_LOCKKEY_UNLOCK;
|
||||
}
|
||||
|
||||
value = _PRS_ASYNC_CH_CTRL_AUXSEL_DEFAULT << _PRS_ASYNC_CH_CTRL_AUXSEL_SHIFT
|
||||
| _PRS_ASYNC_CH_CTRL_FNSEL_A << _PRS_ASYNC_CH_CTRL_FNSEL_SHIFT
|
||||
| _PRS_ASYNC_CH_CTRL_SOURCESEL_HFXO0L << _PRS_ASYNC_CH_CTRL_SOURCESEL_SHIFT
|
||||
| _PRS_ASYNC_CH_CTRL_SIGSEL_HFXO0LSTATUS << _PRS_ASYNC_CH_CTRL_SIGSEL_SHIFT;
|
||||
|
||||
mask = _PRS_ASYNC_CH_CTRL_AUXSEL_MASK
|
||||
| _PRS_ASYNC_CH_CTRL_FNSEL_MASK
|
||||
| _PRS_ASYNC_CH_CTRL_SOURCESEL_MASK
|
||||
| _PRS_ASYNC_CH_CTRL_SIGSEL_MASK;
|
||||
|
||||
BUS_RegMaskedWrite(&(PRS->ASYNC_CH[HFXO_CRYSTSAL_SHARING_PRS_CHANNEL].CTRL), mask, value);
|
||||
|
||||
GPIO_PinModeSet(port, pin, gpioModeWiredOrPullDown, 0U);
|
||||
|
||||
(&(GPIO->PRSROUTE[0].ASYNCH0ROUTE))[HFXO_CRYSTSAL_SHARING_PRS_CHANNEL] = pin << _GPIO_PRS_ASYNCH0ROUTE_PIN_SHIFT
|
||||
| port << _GPIO_PRS_ASYNCH0ROUTE_PORT_SHIFT;
|
||||
GPIO->PRSROUTE[0].ROUTEEN = 1U << (_GPIO_PRS_ROUTEEN_ASYNCH0PEN_SHIFT + HFXO_CRYSTSAL_SHARING_PRS_CHANNEL);
|
||||
|
||||
//sl_clock_manager_disable_bus_clock(SL_BUS_CLOCK_PRS);
|
||||
#elif defined(SL_CLOCK_MANAGER_HFXO_CRYSTAL_SHARING_LEADER_EN) && (SL_CLOCK_MANAGER_HFXO_CRYSTAL_SHARING_LEADER_EN == 1)
|
||||
EFM_ASSERT(GPIO_PORT_PIN_VALID(port, pin));
|
||||
|
||||
// Configure Bufout request GPIO.
|
||||
GPIO_PinModeSet(port, pin, gpioModeInput, 0U);
|
||||
|
||||
GPIO->SYXOROUTE[0].BUFOUTREQINASYNCROUTE = pin << _GPIO_SYXO_BUFOUTREQINASYNCROUTE_PIN_SHIFT
|
||||
| port << _GPIO_SYXO_BUFOUTREQINASYNCROUTE_PORT_SHIFT;
|
||||
|
||||
bool was_locked = HFXO0->STATUS & HFXO_STATUS_LOCK_LOCKED ? true : false;
|
||||
|
||||
// Unlock register interface.
|
||||
HFXO0->LOCK = HFXO_LOCK_LOCKKEY_UNLOCK;
|
||||
|
||||
HFXO0->CTRL_CLR = _HFXO_CTRL_BUFOUTFREEZE_MASK | _HFXO_CTRL_DISONDEMANDBUFOUT_MASK;
|
||||
|
||||
BUS_RegMaskedWrite(&HFXO0->BUFOUTCTRL,
|
||||
_HFXO_BUFOUTCTRL_MINIMUMSTARTUPDELAY_MASK
|
||||
| _HFXO_BUFOUTCTRL_TIMEOUTSTARTUP_MASK,
|
||||
((uint32_t)SL_CLOCK_MANAGER_HFXO_CRYSTAL_SHARING_LEADER_MIN_STARTUP_DELAY_EN) << _HFXO_BUFOUTCTRL_MINIMUMSTARTUPDELAY_SHIFT
|
||||
| SL_CLOCK_MANAGER_HFXO_CRYSTAL_SHARING_LEADER_TIMEOUT_STARTUP);
|
||||
|
||||
if (was_locked) {
|
||||
HFXO0->LOCK = ~HFXO_LOCK_LOCKKEY_UNLOCK;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
SystemHFXOClockSet(SL_CLOCK_MANAGER_HFXO_FREQ);
|
||||
CMU_HFXOInit(&clock_manager_hfxo_init);
|
||||
CMU_HFXOPrecisionSet(SL_CLOCK_MANAGER_HFXO_PRECISION);
|
||||
|
||||
#if defined(SLI_CLOCK_MANAGER_RUNTIME_CONFIGURATION)
|
||||
if (SLI_CLOCK_MANAGER_HFXO_CTUNE_FIXED_STEADY == SLI_CLOCK_MANAGER_HFXO_CTUNE_FIXED_STEADY_DEFAULT) {
|
||||
SLI_CLOCK_MANAGER_HFXO_CTUNE_FIXED_STEADY = (HFXO0->XTALCTRL & _HFXO_XTALCTRL_CTUNEFIXANA_MASK) >> _HFXO_XTALCTRL_CTUNEFIXANA_SHIFT;
|
||||
}
|
||||
#endif
|
||||
|
||||
return SL_STATUS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(LFXO_PRESENT) \
|
||||
&& defined(SL_CLOCK_MANAGER_LFXO_EN) && SL_CLOCK_MANAGER_LFXO_EN == 1
|
||||
/***************************************************************************//**
|
||||
* Initializes LFXO Oscillator.
|
||||
******************************************************************************/
|
||||
FUNCTION_SCOPE sl_status_t init_lfxo(void)
|
||||
{
|
||||
CMU_LFXOInit_TypeDef clock_manager_lfxo_init = CMU_LFXOINIT_DEFAULT;
|
||||
|
||||
clock_manager_lfxo_init.mode = SL_CLOCK_MANAGER_LFXO_MODE >> _LFXO_CFG_MODE_SHIFT;
|
||||
clock_manager_lfxo_init.timeout = SL_CLOCK_MANAGER_LFXO_TIMEOUT >> _LFXO_CFG_TIMEOUT_SHIFT;
|
||||
clock_manager_lfxo_init.capTune = 0xFF;
|
||||
|
||||
#ifndef _SILICON_LABS_32B_SERIES_2_CONFIG_9
|
||||
#if defined(_DEVINFO_MODXOCAL_LFXOCAPTUNE_MASK)
|
||||
// Use LFXO tuning value from DEVINFO if available (PCB modules)
|
||||
if ((DEVINFO->MODULEINFO & _DEVINFO_MODULEINFO_LFXOCALVAL_MASK) == _DEVINFO_MODULEINFO_LFXOCALVAL_VALID) {
|
||||
clock_manager_lfxo_init.capTune = DEVINFO->MODXOCAL & _DEVINFO_MODXOCAL_LFXOCAPTUNE_MASK;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if ((clock_manager_lfxo_init.capTune == 0xFF)
|
||||
#if defined(SL_CLOCK_MANAGER_CTUNE_MFG_LFXO_EN)
|
||||
&& (SL_CLOCK_MANAGER_CTUNE_MFG_LFXO_EN == 1)
|
||||
#endif
|
||||
&& (MFG_CTUNE_LFXO_VAL <= (_LFXO_CAL_CAPTUNE_MASK >> _LFXO_CAL_CAPTUNE_SHIFT))) {
|
||||
clock_manager_lfxo_init.capTune = MFG_CTUNE_LFXO_VAL;
|
||||
}
|
||||
|
||||
if (clock_manager_lfxo_init.capTune == 0xFF) {
|
||||
clock_manager_lfxo_init.capTune = SL_CLOCK_MANAGER_LFXO_CTUNE;
|
||||
}
|
||||
|
||||
CMU_LFXOInit(&clock_manager_lfxo_init);
|
||||
CMU_LFXOPrecisionSet(SL_CLOCK_MANAGER_LFXO_PRECISION);
|
||||
|
||||
return SL_STATUS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
/***************************************************************************//**
|
||||
* Initializes Clock Input CLKIN0.
|
||||
******************************************************************************/
|
||||
static sl_status_t init_clkin0(void)
|
||||
{
|
||||
sl_status_t status = SL_STATUS_OK;
|
||||
|
||||
#if (defined(SL_CLOCK_MANAGER_SYSCLK_SOURCE) && (SL_CLOCK_MANAGER_SYSCLK_SOURCE == CMU_SYSCLKCTRL_CLKSEL_CLKIN0)) \
|
||||
|| (defined(SL_CLOCK_MANAGER_DPLL_REFCLK) && (SL_CLOCK_MANAGER_DPLL_REFCLK == CMU_DPLLREFCLKCTRL_CLKSEL_CLKIN0)) \
|
||||
|| (defined(SL_CLOCK_MANAGER_EM01GRPBCLK_SOURCE) && (SL_CLOCK_MANAGER_EM01GRPBCLK_SOURCE == CMU_EM01GRPBCLKCTRL_CLKSEL_CLKIN0))
|
||||
|
||||
#if !defined(SL_CLOCK_MANAGER_CLKIN0_PORT) || !defined(SL_CLOCK_MANAGER_CLKIN0_PIN)
|
||||
#error "Invalid configuration: CLKIN0 reference can't be use without configuring SL_CLOCK_MANAGER_CLKIN0 with a valid port and pin."
|
||||
#endif
|
||||
|
||||
sl_gpio_t clkin0_gpio = { SL_CLOCK_MANAGER_CLKIN0_PORT, SL_CLOCK_MANAGER_CLKIN0_PIN };
|
||||
|
||||
status = sl_clock_manager_enable_bus_clock(SL_BUS_CLOCK_GPIO);
|
||||
if (status != SL_STATUS_OK) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = sl_gpio_set_pin_mode(&clkin0_gpio, SL_GPIO_MODE_INPUT, false);
|
||||
if (status == SL_STATUS_OK) {
|
||||
GPIO->CMUROUTE.CLKIN0ROUTE = (clkin0_gpio.port << _GPIO_CMU_CLKIN0ROUTE_PORT_SHIFT)
|
||||
| (clkin0_gpio.pin << _GPIO_CMU_CLKIN0ROUTE_PIN_SHIFT);
|
||||
}
|
||||
#endif
|
||||
return status;
|
||||
}
|
||||
|
||||
#if defined(HFRCO_PRESENT)
|
||||
/***************************************************************************//**
|
||||
* Initializes HFRCODPLL Oscillator.
|
||||
******************************************************************************/
|
||||
FUNCTION_SCOPE sl_status_t init_hfrcodpll(void)
|
||||
{
|
||||
#if defined(SL_CLOCK_MANAGER_HFRCO_DPLL_EN) && (SL_CLOCK_MANAGER_HFRCO_DPLL_EN == 1)
|
||||
CMU_DPLLInit_TypeDef clock_manager_dpll_init = {
|
||||
.frequency = SL_CLOCK_MANAGER_DPLL_FREQ,
|
||||
.n = SL_CLOCK_MANAGER_DPLL_N,
|
||||
.m = SL_CLOCK_MANAGER_DPLL_M,
|
||||
.edgeSel = SL_CLOCK_MANAGER_DPLL_EDGE,
|
||||
.lockMode = SL_CLOCK_MANAGER_DPLL_LOCKMODE,
|
||||
.autoRecover = SL_CLOCK_MANAGER_DPLL_AUTORECOVER,
|
||||
.ditherEn = SL_CLOCK_MANAGER_DPLL_DITHER
|
||||
};
|
||||
|
||||
// Convert the DPLL Reference clock configuration to emlib CMU_Select_TypeDef type.
|
||||
switch (SL_CLOCK_MANAGER_DPLL_REFCLK) {
|
||||
case CMU_DPLLREFCLKCTRL_CLKSEL_HFXO:
|
||||
clock_manager_dpll_init.refClk = cmuSelect_HFXO;
|
||||
break;
|
||||
case CMU_DPLLREFCLKCTRL_CLKSEL_LFXO:
|
||||
clock_manager_dpll_init.refClk = cmuSelect_LFXO;
|
||||
break;
|
||||
case CMU_DPLLREFCLKCTRL_CLKSEL_CLKIN0:
|
||||
clock_manager_dpll_init.refClk = cmuSelect_CLKIN0;
|
||||
break;
|
||||
default:
|
||||
return SL_STATUS_INVALID_CONFIGURATION;
|
||||
}
|
||||
|
||||
CMU_Select_TypeDef selected_sysclk = CMU_ClockSelectGet(cmuClock_SYSCLK);
|
||||
|
||||
if (selected_sysclk == cmuSelect_HFRCODPLL) {
|
||||
// The CMU should not be running from the HFRCO. If necessary, the CMU
|
||||
// should switch to the FSRCO until after the DPLL has locked to avoid
|
||||
// over-clocking due to overshoot.
|
||||
CMU->SYSCLKCTRL = (CMU->SYSCLKCTRL & ~_CMU_SYSCLKCTRL_CLKSEL_MASK) | CMU_SYSCLKCTRL_CLKSEL_FSRCO;
|
||||
}
|
||||
|
||||
#if (_SILICON_LABS_32B_SERIES_2_CONFIG > 1)
|
||||
CMU_ClockEnable(cmuClock_DPLL0, true);
|
||||
#endif
|
||||
|
||||
bool success = CMU_DPLLLock(&clock_manager_dpll_init);
|
||||
|
||||
// If CMU was initially running from HFRCO switch back from FSRCO.
|
||||
if (selected_sysclk == cmuSelect_HFRCODPLL) {
|
||||
CMU->SYSCLKCTRL = (CMU->SYSCLKCTRL & ~_CMU_SYSCLKCTRL_CLKSEL_MASK) | CMU_SYSCLKCTRL_CLKSEL_HFRCODPLL;
|
||||
}
|
||||
|
||||
// If DPLL lock was unsuccessful, return status fail.
|
||||
if (!success) {
|
||||
// Disable DPLL0 if lock failed.
|
||||
#if (_SILICON_LABS_32B_SERIES_2_CONFIG > 1)
|
||||
CMU_ClockEnable(cmuClock_DPLL0, false);
|
||||
#endif
|
||||
return SL_STATUS_FAIL;
|
||||
}
|
||||
#else
|
||||
CMU_HFRCODPLLBandSet(SLI_CLOCK_MANAGER_HFRCO_BAND);
|
||||
#endif
|
||||
return SL_STATUS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HFRCOEM23_PRESENT)
|
||||
/***************************************************************************//**
|
||||
* Initializes HFRCOEM23 Oscillator.
|
||||
******************************************************************************/
|
||||
FUNCTION_SCOPE sl_status_t init_hfrcoem23(void)
|
||||
{
|
||||
CMU_HFRCOEM23BandSet(SL_CLOCK_MANAGER_HFRCOEM23_BAND);
|
||||
|
||||
return SL_STATUS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(LFRCO_PRESENT)
|
||||
/***************************************************************************//**
|
||||
* Initializes LFRCO Oscillator.
|
||||
******************************************************************************/
|
||||
FUNCTION_SCOPE sl_status_t init_lfrco(void)
|
||||
{
|
||||
#if (_SILICON_LABS_32B_SERIES_2_CONFIG > 1)
|
||||
CMU_ClockEnable(cmuClock_LFRCO, true);
|
||||
#endif
|
||||
|
||||
#if defined(PLFRCO_PRESENT)
|
||||
#if !(defined(SL_CLOCK_MANAGER_HFXO_EN) && (SL_CLOCK_MANAGER_HFXO_EN == 1))
|
||||
EFM_ASSERT(SL_CLOCK_MANAGER_LFRCO_PRECISION != cmuPrecisionHigh);
|
||||
#endif
|
||||
CMU_LFRCOSetPrecision(SL_CLOCK_MANAGER_LFRCO_PRECISION);
|
||||
#endif
|
||||
|
||||
return SL_STATUS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(RFFPLL_PRESENT) \
|
||||
&& defined(SL_CLOCK_MANAGER_HFXO_EN) && (SL_CLOCK_MANAGER_HFXO_EN == 1)
|
||||
/***************************************************************************//**
|
||||
* Initializes RFFPLL Oscillator.
|
||||
******************************************************************************/
|
||||
FUNCTION_SCOPE sl_status_t init_rffpll(void)
|
||||
{
|
||||
CMU_RFFPLL_Init_TypeDef rffpll_init = CMU_RFFPLL_DEFAULT;
|
||||
|
||||
// Overwrite default configurations.
|
||||
#if (SL_CLOCK_MANAGER_RFFPLL_CUSTOM_BAND == 1)
|
||||
// Custom settings provided by the user.
|
||||
rffpll_init.frequency = SL_CLOCK_MANAGER_RFFPLL_FREQ;
|
||||
rffpll_init.dividerY = SL_CLOCK_MANAGER_RFFPLL_DIV_Y;
|
||||
rffpll_init.dividerX = SL_CLOCK_MANAGER_RFFPLL_DIV_X;
|
||||
rffpll_init.dividerN = SL_CLOCK_MANAGER_RFFPLL_DIV_N;
|
||||
#elif (SL_CLOCK_MANAGER_RFFPLL_BAND == 7) && defined(RADIO_CONFIG_RFFPLL_CONFIG_PRESENT)
|
||||
// Settings from the RAIL lib.
|
||||
rffpll_init.frequency = radioConfigRffpllConfig->sysclkFreqHz;
|
||||
rffpll_init.dividerY = ((radioConfigRffpllConfig->dividers & RAIL_RFFPLL_DIVIDERY_MASK) >> RAIL_RFFPLL_DIVIDERY_SHIFT);
|
||||
rffpll_init.dividerX = ((radioConfigRffpllConfig->dividers & RAIL_RFFPLL_DIVIDERX_MASK) >> RAIL_RFFPLL_DIVIDERX_SHIFT);
|
||||
rffpll_init.dividerN = ((radioConfigRffpllConfig->dividers & RAIL_RFFPLL_DIVIDERN_MASK) >> RAIL_RFFPLL_DIVIDERN_SHIFT);
|
||||
#else
|
||||
// Pre-determined settings.
|
||||
rffpll_init.frequency = rffpll_band_config_39MHz[SL_CLOCK_MANAGER_RFFPLL_BAND].frequency;
|
||||
rffpll_init.dividerY = rffpll_band_config_39MHz[SL_CLOCK_MANAGER_RFFPLL_BAND].divider_y;
|
||||
rffpll_init.dividerX = rffpll_band_config_39MHz[SL_CLOCK_MANAGER_RFFPLL_BAND].divider_x;
|
||||
rffpll_init.dividerN = rffpll_band_config_39MHz[SL_CLOCK_MANAGER_RFFPLL_BAND].divider_n;
|
||||
#endif
|
||||
|
||||
// Initialize RFFPLL.
|
||||
CMU_RFFPLLInit(&rffpll_init);
|
||||
|
||||
// Update RFFPLL frequency in System file
|
||||
SystemRFFPLLClockSet(rffpll_init.frequency);
|
||||
|
||||
// At this point, RFFPLL has been initialized. The clock source for SYSCLK can be
|
||||
// RFFPLLSYS input clock. If you want RFFPLLSYS, configure SL_CLOCK_MANAGER_SYSCLK_SOURCE
|
||||
// to CMU_SYSCLKCTRL_CLKSEL_RFFPLL0SYS.
|
||||
|
||||
return SL_STATUS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(USBPLL_PRESENT) \
|
||||
&& defined(SL_CLOCK_MANAGER_HFXO_EN) && (SL_CLOCK_MANAGER_HFXO_EN == 1)
|
||||
/***************************************************************************//**
|
||||
* Initializes USBPLL Oscillator.
|
||||
******************************************************************************/
|
||||
FUNCTION_SCOPE sl_status_t init_usbpll(void)
|
||||
{
|
||||
CMU_USBPLL_Init_TypeDef usbpll_config;
|
||||
uint32_t hfxo_freq = SystemHFXOClockGet();
|
||||
|
||||
// Validate that HFXO frequency is adequate for USB PLL and set the right frequency.
|
||||
switch (hfxo_freq) {
|
||||
case 38000000:
|
||||
usbpll_config.hfxoRefFreq = cmuHFXORefFreq_38M0Hz;
|
||||
break;
|
||||
|
||||
case 38400000:
|
||||
usbpll_config.hfxoRefFreq = cmuHFXORefFreq_38M4Hz;
|
||||
break;
|
||||
|
||||
case 39000000:
|
||||
usbpll_config.hfxoRefFreq = cmuHFXORefFreq_39M0Hz;
|
||||
break;
|
||||
|
||||
case 40000000:
|
||||
usbpll_config.hfxoRefFreq = cmuHFXORefFreq_40M0Hz;
|
||||
break;
|
||||
|
||||
default:
|
||||
return SL_STATUS_FAIL;
|
||||
}
|
||||
|
||||
// Set additional configurations.
|
||||
usbpll_config.shuntRegEn = false;
|
||||
usbpll_config.disOnDemand = false;
|
||||
usbpll_config.regLock = true;
|
||||
|
||||
// Set Force Enable feature at first to force the PLL to start and validate it works.
|
||||
usbpll_config.forceEn = true;
|
||||
|
||||
// Initialize USB PLL and wait for it to be ready.
|
||||
CMU_USBPLLInit(&usbpll_config);
|
||||
|
||||
// Remove the Force Enable feature to let PLL module on-demand.
|
||||
usbpll_config.forceEn = false;
|
||||
|
||||
// Re-initialized without the Force Enable feature.
|
||||
CMU_USBPLLInit(&usbpll_config);
|
||||
|
||||
return SL_STATUS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
/***************************************************************************//**
|
||||
* Initializes Clock branches.
|
||||
******************************************************************************/
|
||||
FUNCTION_SCOPE sl_status_t init_clock_branches(void)
|
||||
{
|
||||
// Initialize SYSCLK clock branch.
|
||||
#if defined(SL_CLOCK_MANAGER_SYSCLK_SOURCE)
|
||||
sli_em_cmu_SYSCLKInitPreClockSelect();
|
||||
#if (SL_CLOCK_MANAGER_SYSCLK_SOURCE == SL_CLOCK_MANAGER_DEFAULT_HF_CLOCK_SOURCE)
|
||||
CLOCK_MANAGER_CLOCK_SELECT_SET(SYSCLK, CLOCK_MANAGER_GET_DEFAULT_CLOCK_SOURCE(SYSCLK, SL_CLOCK_MANAGER_DEFAULT_HF_CLOCK_SOURCE_CONCATENATION));
|
||||
#else
|
||||
CLOCK_MANAGER_CLOCK_SELECT_SET(SYSCLK, SL_CLOCK_MANAGER_SYSCLK_SOURCE);
|
||||
#endif
|
||||
sli_em_cmu_SYSCLKInitPostClockSelect(false);
|
||||
CMU->SYSCLKCTRL = (CMU->SYSCLKCTRL & ~(_CMU_SYSCLKCTRL_HCLKPRESC_MASK | _CMU_SYSCLKCTRL_PCLKPRESC_MASK))
|
||||
| SL_CLOCK_MANAGER_HCLK_DIVIDER
|
||||
| SL_CLOCK_MANAGER_PCLK_DIVIDER;
|
||||
#else
|
||||
EFM_ASSERT(false);
|
||||
#endif
|
||||
|
||||
// Initialize TRACECLK clock branch.
|
||||
#if defined(CoreDebug_DEMCR_TRCENA_Msk)
|
||||
// Disable the Core Debug module if already enabled
|
||||
bool trace_on = CoreDebug->DEMCR & CoreDebug_DEMCR_TRCENA_Msk;
|
||||
if (trace_on) {
|
||||
CoreDebug->DEMCR &= ~CoreDebug_DEMCR_TRCENA_Msk;
|
||||
}
|
||||
#endif
|
||||
#if defined(SL_CLOCK_MANAGER_TRACECLK_SOURCE)
|
||||
CLOCK_MANAGER_CLOCK_SELECT_SET(TRACECLK, SL_CLOCK_MANAGER_TRACECLK_SOURCE);
|
||||
#endif
|
||||
#if defined(SL_CLOCK_MANAGER_TRACECLK_DIVIDER)
|
||||
CMU->TRACECLKCTRL |= SL_CLOCK_MANAGER_TRACECLK_DIVIDER;
|
||||
#endif
|
||||
#if defined(CoreDebug_DEMCR_TRCENA_Msk)
|
||||
// Enable back the Core Debug module if it was already enabled
|
||||
if (trace_on) {
|
||||
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
|
||||
}
|
||||
#endif
|
||||
// Ensure TraceClk configs are defined if TraceClk is present.
|
||||
#if defined(_CMU_TRACECLKCTRL_MASK) && !(defined(SL_CLOCK_MANAGER_TRACECLK_SOURCE) || defined(SL_CLOCK_MANAGER_TRACECLK_DIVIDER))
|
||||
EFM_ASSERT(false);
|
||||
#endif
|
||||
|
||||
// Initialize EM01GRPACLK clock branch.
|
||||
#if defined(SL_CLOCK_MANAGER_EM01GRPACLK_SOURCE)
|
||||
#if (SL_CLOCK_MANAGER_EM01GRPACLK_SOURCE == SL_CLOCK_MANAGER_DEFAULT_HF_CLOCK_SOURCE)
|
||||
CLOCK_MANAGER_CLOCK_SELECT_SET(EM01GRPACLK, CLOCK_MANAGER_GET_DEFAULT_CLOCK_SOURCE(EM01GRPACLK, SL_CLOCK_MANAGER_DEFAULT_HF_CLOCK_SOURCE_CONCATENATION));
|
||||
#else
|
||||
CLOCK_MANAGER_CLOCK_SELECT_SET(EM01GRPACLK, SL_CLOCK_MANAGER_EM01GRPACLK_SOURCE);
|
||||
#endif
|
||||
#else
|
||||
EFM_ASSERT(false);
|
||||
#endif
|
||||
|
||||
// Initialize EM01GRPBCLK clock branch.
|
||||
#if defined(PDM_PRESENT)
|
||||
#if defined(SL_CLOCK_MANAGER_EM01GRPBCLK_SOURCE)
|
||||
#if (SL_CLOCK_MANAGER_EM01GRPBCLK_SOURCE == SL_CLOCK_MANAGER_DEFAULT_HF_CLOCK_SOURCE)
|
||||
CLOCK_MANAGER_CLOCK_SELECT_SET(EM01GRPBCLK, CLOCK_MANAGER_GET_DEFAULT_CLOCK_SOURCE(EM01GRPBCLK, SL_CLOCK_MANAGER_DEFAULT_HF_CLOCK_SOURCE_CONCATENATION));
|
||||
#else
|
||||
CLOCK_MANAGER_CLOCK_SELECT_SET(EM01GRPBCLK, SL_CLOCK_MANAGER_EM01GRPBCLK_SOURCE);
|
||||
#endif
|
||||
#else
|
||||
EFM_ASSERT(false);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Initialize EM01GRPCCLK clock branch.
|
||||
#if defined(_CMU_EM01GRPCCLKCTRL_MASK)
|
||||
#if defined(SL_CLOCK_MANAGER_EM01GRPCCLK_SOURCE)
|
||||
#if (SL_CLOCK_MANAGER_EM01GRPCCLK_SOURCE == SL_CLOCK_MANAGER_DEFAULT_HF_CLOCK_SOURCE)
|
||||
CLOCK_MANAGER_CLOCK_SELECT_SET(EM01GRPCCLK, CLOCK_MANAGER_GET_DEFAULT_CLOCK_SOURCE(EM01GRPCCLK, SL_CLOCK_MANAGER_DEFAULT_HF_CLOCK_SOURCE_CONCATENATION));
|
||||
#else
|
||||
CLOCK_MANAGER_CLOCK_SELECT_SET(EM01GRPCCLK, SL_CLOCK_MANAGER_EM01GRPCCLK_SOURCE);
|
||||
#endif
|
||||
#else
|
||||
EFM_ASSERT(false);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Initialize IADCCLK clock branch.
|
||||
#if defined(SL_CLOCK_MANAGER_IADCCLK_SOURCE)
|
||||
CLOCK_MANAGER_CLOCK_SELECT_SET(IADCCLK, SL_CLOCK_MANAGER_IADCCLK_SOURCE);
|
||||
#else
|
||||
EFM_ASSERT(false);
|
||||
#endif
|
||||
|
||||
// Initialize LESENSEHFCLK clock branch.
|
||||
#if defined(LESENSE_PRESENT)
|
||||
#if defined(SL_CLOCK_MANAGER_LESENSEHFCLK_SOURCE)
|
||||
CLOCK_MANAGER_CLOCK_SELECT_SET(LESENSEHFCLK, SL_CLOCK_MANAGER_LESENSEHFCLK_SOURCE);
|
||||
#else
|
||||
EFM_ASSERT(false);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Initialize EM23GRPACLK clock branch.
|
||||
#if defined(SL_CLOCK_MANAGER_EM23GRPACLK_SOURCE)
|
||||
#if (SL_CLOCK_MANAGER_EM23GRPACLK_SOURCE == SL_CLOCK_MANAGER_DEFAULT_LF_CLOCK_SOURCE)
|
||||
CLOCK_MANAGER_CLOCK_SELECT_SET(EM23GRPACLK, CLOCK_MANAGER_GET_DEFAULT_CLOCK_SOURCE(EM23GRPACLK, SL_CLOCK_MANAGER_DEFAULT_LF_CLOCK_SOURCE_CONCATENATION));
|
||||
#else
|
||||
CLOCK_MANAGER_CLOCK_SELECT_SET(EM23GRPACLK, SL_CLOCK_MANAGER_EM23GRPACLK_SOURCE);
|
||||
#endif
|
||||
#else
|
||||
EFM_ASSERT(false);
|
||||
#endif
|
||||
|
||||
// Initialize EM4GRPACLK clock branch.
|
||||
#if defined(SL_CLOCK_MANAGER_EM4GRPACLK_SOURCE)
|
||||
#if (SL_CLOCK_MANAGER_EM4GRPACLK_SOURCE == SL_CLOCK_MANAGER_DEFAULT_LF_CLOCK_SOURCE)
|
||||
CLOCK_MANAGER_CLOCK_SELECT_SET(EM4GRPACLK, CLOCK_MANAGER_GET_DEFAULT_CLOCK_SOURCE(EM4GRPACLK, SL_CLOCK_MANAGER_DEFAULT_LF_CLOCK_SOURCE_CONCATENATION));
|
||||
#else
|
||||
CLOCK_MANAGER_CLOCK_SELECT_SET(EM4GRPACLK, SL_CLOCK_MANAGER_EM4GRPACLK_SOURCE);
|
||||
#endif
|
||||
#else
|
||||
EFM_ASSERT(false);
|
||||
#endif
|
||||
|
||||
// Initialize RTCC clock branch.
|
||||
#if defined(RTCC_PRESENT)
|
||||
#if defined(SL_CLOCK_MANAGER_RTCCCLK_SOURCE)
|
||||
#if (SL_CLOCK_MANAGER_RTCCCLK_SOURCE == SL_CLOCK_MANAGER_DEFAULT_LF_CLOCK_SOURCE)
|
||||
CLOCK_MANAGER_CLOCK_SELECT_SET(RTCCCLK, CLOCK_MANAGER_GET_DEFAULT_CLOCK_SOURCE(RTCCCLK, SL_CLOCK_MANAGER_DEFAULT_LF_CLOCK_SOURCE_CONCATENATION));
|
||||
#else
|
||||
CLOCK_MANAGER_CLOCK_SELECT_SET(RTCCCLK, SL_CLOCK_MANAGER_RTCCCLK_SOURCE);
|
||||
#endif
|
||||
#else
|
||||
EFM_ASSERT(false);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Initialize SYSRTC clock branch.
|
||||
#if defined(SYSRTC_PRESENT)
|
||||
#if defined(SL_CLOCK_MANAGER_SYSRTCCLK_SOURCE)
|
||||
#if (SL_CLOCK_MANAGER_SYSRTCCLK_SOURCE == SL_CLOCK_MANAGER_DEFAULT_LF_CLOCK_SOURCE)
|
||||
CLOCK_MANAGER_CLOCK_SELECT_SET(SYSRTC0CLK, CLOCK_MANAGER_GET_DEFAULT_CLOCK_SOURCE(SYSRTC0CLK, SL_CLOCK_MANAGER_DEFAULT_LF_CLOCK_SOURCE_CONCATENATION));
|
||||
#else
|
||||
CLOCK_MANAGER_CLOCK_SELECT_SET(SYSRTC0CLK, SL_CLOCK_MANAGER_SYSRTCCLK_SOURCE);
|
||||
#endif
|
||||
#else
|
||||
EFM_ASSERT(false);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Initialize WDOG0 clock branch.
|
||||
#if defined(SL_CLOCK_MANAGER_WDOG0CLK_SOURCE)
|
||||
#if (SL_CLOCK_MANAGER_WDOG0CLK_SOURCE == SL_CLOCK_MANAGER_DEFAULT_LF_CLOCK_SOURCE)
|
||||
CLOCK_MANAGER_CLOCK_SELECT_SET(WDOG0CLK, CLOCK_MANAGER_GET_DEFAULT_CLOCK_SOURCE(WDOG0CLK, SL_CLOCK_MANAGER_DEFAULT_LF_CLOCK_SOURCE_CONCATENATION));
|
||||
#else
|
||||
CLOCK_MANAGER_CLOCK_SELECT_SET(WDOG0CLK, SL_CLOCK_MANAGER_WDOG0CLK_SOURCE);
|
||||
#endif
|
||||
#else
|
||||
EFM_ASSERT(false);
|
||||
#endif
|
||||
|
||||
// Initialize WDOG1 clock branch.
|
||||
#if WDOG_COUNT > 1
|
||||
#if defined(SL_CLOCK_MANAGER_WDOG1CLK_SOURCE)
|
||||
#if (SL_CLOCK_MANAGER_WDOG1CLK_SOURCE == SL_CLOCK_MANAGER_DEFAULT_LF_CLOCK_SOURCE)
|
||||
CLOCK_MANAGER_CLOCK_SELECT_SET(WDOG1CLK, CLOCK_MANAGER_GET_DEFAULT_CLOCK_SOURCE(WDOG1CLK, SL_CLOCK_MANAGER_DEFAULT_LF_CLOCK_SOURCE_CONCATENATION));
|
||||
#else
|
||||
CLOCK_MANAGER_CLOCK_SELECT_SET(WDOG1CLK, SL_CLOCK_MANAGER_WDOG1CLK_SOURCE);
|
||||
#endif
|
||||
#else
|
||||
EFM_ASSERT(false);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Initialize LCD clock branch.
|
||||
#if defined(LCD_PRESENT)
|
||||
#if defined(SL_CLOCK_MANAGER_LCDCLK_SOURCE)
|
||||
#if (SL_CLOCK_MANAGER_LCDCLK_SOURCE == SL_CLOCK_MANAGER_DEFAULT_LF_CLOCK_SOURCE)
|
||||
CLOCK_MANAGER_CLOCK_SELECT_SET(LCDCLK, CLOCK_MANAGER_GET_DEFAULT_CLOCK_SOURCE(LCDCLK, SL_CLOCK_MANAGER_DEFAULT_LF_CLOCK_SOURCE_CONCATENATION));
|
||||
#else
|
||||
CLOCK_MANAGER_CLOCK_SELECT_SET(LCDCLK, SL_CLOCK_MANAGER_LCDCLK_SOURCE);
|
||||
#endif
|
||||
#else
|
||||
EFM_ASSERT(false);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Initialize PCNT0 clock branch.
|
||||
#if defined(PCNT_PRESENT)
|
||||
#if defined(SL_CLOCK_MANAGER_PCNT0CLK_SOURCE)
|
||||
CLOCK_MANAGER_CLOCK_SELECT_SET(PCNT0CLK, SL_CLOCK_MANAGER_PCNT0CLK_SOURCE);
|
||||
#else
|
||||
EFM_ASSERT(false);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Initialize EUSART0
|
||||
#if defined(EUSART_PRESENT)
|
||||
#if defined(SL_CLOCK_MANAGER_EUSART0CLK_SOURCE)
|
||||
CLOCK_MANAGER_CLOCK_SELECT_SET(EUSART0CLK, SL_CLOCK_MANAGER_EUSART0CLK_SOURCE);
|
||||
#else
|
||||
EFM_ASSERT(false);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Initialize EUART
|
||||
#if defined(EUART_PRESENT)
|
||||
#if defined(SL_CLOCK_MANAGER_EUART0CLK_SOURCE)
|
||||
CLOCK_MANAGER_CLOCK_SELECT_SET(EUART0CLK, SL_CLOCK_MANAGER_EUART0CLK_SOURCE);
|
||||
#else
|
||||
EFM_ASSERT(false);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Initialize SYSTICK clock branch.
|
||||
#if defined(SL_CLOCK_MANAGER_SYSTICKCLK_SOURCE)
|
||||
#if (SL_CLOCK_MANAGER_SYSTICKCLK_SOURCE == 1)
|
||||
CMU_CLOCK_SELECT_SET(SYSTICK, EM23GRPACLK);
|
||||
#elif (SL_CLOCK_MANAGER_SYSTICKCLK_SOURCE == 0)
|
||||
CMU_CLOCK_SELECT_SET(SYSTICK, HCLK);
|
||||
#else
|
||||
EFM_ASSERT(false);
|
||||
#endif
|
||||
#else
|
||||
EFM_ASSERT(false);
|
||||
#endif
|
||||
|
||||
// Initialize VDAC0 clock branch.
|
||||
#if defined(VDAC_PRESENT)
|
||||
#if defined(SL_CLOCK_MANAGER_VDAC0CLK_SOURCE)
|
||||
CLOCK_MANAGER_CLOCK_SELECT_SET(VDAC0CLK, SL_CLOCK_MANAGER_VDAC0CLK_SOURCE);
|
||||
#else
|
||||
EFM_ASSERT(false);
|
||||
#endif
|
||||
|
||||
// Initialize VDAC1 clock branch.
|
||||
#if VDAC_COUNT > 1
|
||||
#if defined(SL_CLOCK_MANAGER_VDAC1CLK_SOURCE)
|
||||
CLOCK_MANAGER_CLOCK_SELECT_SET(VDAC1CLK, SL_CLOCK_MANAGER_VDAC1CLK_SOURCE);
|
||||
#else
|
||||
EFM_ASSERT(false);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return SL_STATUS_OK;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
********************** GLOBAL INTERNAL FUNCTIONS **************************
|
||||
******************************************************************************/
|
||||
|
||||
/***************************************************************************//**
|
||||
* Initializes Oscillators and Clock branches.
|
||||
******************************************************************************/
|
||||
sl_status_t sli_clock_manager_hal_init(void)
|
||||
{
|
||||
sl_status_t status;
|
||||
|
||||
#if defined(SYSRTC_PRESENT)
|
||||
status = sl_clock_manager_enable_bus_clock(SL_BUS_CLOCK_SYSRTC0);
|
||||
if (status != SL_STATUS_OK) {
|
||||
return status;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Initialize Oscillators
|
||||
#if defined(LFXO_PRESENT) \
|
||||
&& defined(SL_CLOCK_MANAGER_LFXO_EN) && (SL_CLOCK_MANAGER_LFXO_EN == 1)
|
||||
status = init_lfxo();
|
||||
if (status != SL_STATUS_OK) {
|
||||
return status;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HFXO_PRESENT) \
|
||||
&& defined(SL_CLOCK_MANAGER_HFXO_EN) && (SL_CLOCK_MANAGER_HFXO_EN == 1)
|
||||
status = init_hfxo();
|
||||
if (status != SL_STATUS_OK) {
|
||||
return status;
|
||||
}
|
||||
#endif
|
||||
|
||||
status = init_clkin0();
|
||||
if (status != SL_STATUS_OK) {
|
||||
return status;
|
||||
}
|
||||
|
||||
#if defined(HFRCO_PRESENT)
|
||||
status = init_hfrcodpll();
|
||||
if (status != SL_STATUS_OK) {
|
||||
return status;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HFRCOEM23_PRESENT)
|
||||
status = init_hfrcoem23();
|
||||
if (status != SL_STATUS_OK) {
|
||||
return status;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(LFRCO_PRESENT)
|
||||
status = init_lfrco();
|
||||
if (status != SL_STATUS_OK) {
|
||||
return status;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(RFFPLL_PRESENT) \
|
||||
&& defined(SL_CLOCK_MANAGER_HFXO_EN) && (SL_CLOCK_MANAGER_HFXO_EN == 1)
|
||||
status = init_rffpll();
|
||||
if (status != SL_STATUS_OK) {
|
||||
return status;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(USBPLL_PRESENT) \
|
||||
&& defined(SL_CLOCK_MANAGER_HFXO_EN) && (SL_CLOCK_MANAGER_HFXO_EN == 1)
|
||||
status = init_usbpll();
|
||||
if (status != SL_STATUS_OK) {
|
||||
return status;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Initialize Clock branches
|
||||
status = init_clock_branches();
|
||||
if (status != SL_STATUS_OK) {
|
||||
return status;
|
||||
}
|
||||
|
||||
return SL_STATUS_OK;
|
||||
}
|
||||
198
Libs/platform/service/clock_manager/src/sli_clock_manager_hal.h
Normal file
198
Libs/platform/service/clock_manager/src/sli_clock_manager_hal.h
Normal file
@@ -0,0 +1,198 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief Clock Manager HAL APIs.
|
||||
*******************************************************************************
|
||||
* # License
|
||||
* <b>Copyright 2023 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_CLOCK_MANAGER_HAL_H
|
||||
#define SL_CLOCK_MANAGER_HAL_H
|
||||
|
||||
#include "sl_clock_manager.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/***************************************************************************//**
|
||||
* Performs Clock Manager runtime initialization.
|
||||
******************************************************************************/
|
||||
sl_status_t sli_clock_manager_hal_runtime_init(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets frequency of given oscillator.
|
||||
******************************************************************************/
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_CLOCK_MANAGER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
sl_status_t sli_clock_manager_hal_get_oscillator_frequency(sl_oscillator_t oscillator,
|
||||
uint32_t *frequency);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets precision of given oscillator.
|
||||
******************************************************************************/
|
||||
sl_status_t sli_clock_manager_hal_get_oscillator_precision(sl_oscillator_t oscillator,
|
||||
uint16_t *precision);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets frequency of given clock branch.
|
||||
******************************************************************************/
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_CLOCK_MANAGER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
sl_status_t sli_clock_manager_hal_get_clock_branch_frequency(sl_clock_branch_t clock_branch,
|
||||
uint32_t *frequency);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets precision of given clock branch.
|
||||
******************************************************************************/
|
||||
sl_status_t sli_clock_manager_hal_get_clock_branch_precision(sl_clock_branch_t clock_branch,
|
||||
uint16_t *precision);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Enables/Disables the bus clock associated with the given module.
|
||||
******************************************************************************/
|
||||
sl_status_t sli_clock_manager_hal_enable_bus_clock(sl_bus_clock_t module,
|
||||
bool enable);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Configures the exported clock feature on CMU to output user selected
|
||||
* clock source specified GPIO pin.
|
||||
******************************************************************************/
|
||||
sl_status_t sli_clock_manager_hal_set_gpio_clock_output(sl_clock_manager_export_clock_source_t export_clock_source,
|
||||
sl_clock_manager_export_clock_output_select_t output_select,
|
||||
uint16_t divider,
|
||||
uint32_t port,
|
||||
uint32_t pin);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Sets the RC oscillator frequency tuning control.
|
||||
******************************************************************************/
|
||||
sl_status_t sli_clock_manager_hal_set_rc_oscillator_calibration(sl_oscillator_t oscillator,
|
||||
uint32_t val);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets the RC oscillator frequency tuning setting.
|
||||
******************************************************************************/
|
||||
sl_status_t sli_clock_manager_hal_get_rc_oscillator_calibration(sl_oscillator_t oscillator,
|
||||
uint32_t *val);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Sets the HFXO calibration value.
|
||||
******************************************************************************/
|
||||
sl_status_t sli_clock_manager_hal_set_hfxo_calibration(uint32_t val);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets the HFXO calibration value.
|
||||
******************************************************************************/
|
||||
sl_status_t sli_clock_manager_hal_get_hfxo_calibration(uint32_t *val);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Sets the HFXO CTUNE setting.
|
||||
******************************************************************************/
|
||||
sl_status_t sli_clock_manager_hal_hfxo_set_ctune(uint32_t ctune);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets the HFXO CTUNE setting.
|
||||
******************************************************************************/
|
||||
sl_status_t sli_clock_manager_hal_hfxo_get_ctune(uint32_t *ctune);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Updates the tuning capacitances and calibrate the Core Bias Current.
|
||||
******************************************************************************/
|
||||
sl_status_t sli_clock_manager_hal_hfxo_calibrate_ctune(uint32_t ctune);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Sets the LFXO frequency tuning control.
|
||||
******************************************************************************/
|
||||
sl_status_t sli_clock_manager_hal_set_lfxo_calibration(uint32_t val);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets the LFXO frequency tuning setting.
|
||||
******************************************************************************/
|
||||
sl_status_t sli_clock_manager_hal_get_lfxo_calibration(uint32_t *val);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Configures the RCO calibration.
|
||||
*****************************************************************************/
|
||||
sl_status_t sli_clock_manager_hal_configure_rco_calibration(uint32_t cycles,
|
||||
sl_clock_manager_clock_calibration_t down_counter_selection,
|
||||
sl_clock_manager_clock_calibration_t up_counter_selection,
|
||||
bool continuous_calibration);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Starts the RCO calibration.
|
||||
******************************************************************************/
|
||||
void sli_clock_manager_hal_start_rco_calibration (void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Stops the RCO calibration.
|
||||
******************************************************************************/
|
||||
void sli_clock_manager_hal_stop_rco_calibration(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Waits for the RCO calibration to finish.
|
||||
******************************************************************************/
|
||||
void sli_clock_manager_hal_wait_rco_calibration(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets calibration count value.
|
||||
******************************************************************************/
|
||||
sl_status_t sli_clock_manager_hal_get_rco_calibration_count(uint32_t *count);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Sets SYSCLK clock source.
|
||||
******************************************************************************/
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_CLOCK_MANAGER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
sl_status_t sli_clock_manager_hal_set_sysclk_source(sl_oscillator_t source);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets SYSCLK clock source.
|
||||
******************************************************************************/
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_CLOCK_MANAGER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
sl_status_t sli_clock_manager_hal_get_sysclk_source(sl_oscillator_t *source);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Waits for USBPLL clock to be ready.
|
||||
******************************************************************************/
|
||||
sl_status_t sli_clock_manager_hal_wait_usbpll(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Sets the external FLASH reference clock.
|
||||
*
|
||||
* @note This API is not thread-safe and should therefore not be called
|
||||
* across multiple tasks.
|
||||
******************************************************************************/
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_CLOCK_MANAGER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
sl_status_t sli_clock_manager_hal_set_ext_flash_clk(sl_oscillator_t oscillator);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets the external FLASH clock source.
|
||||
******************************************************************************/
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_CLOCK_MANAGER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
sl_status_t sli_clock_manager_hal_get_ext_flash_clk(sl_oscillator_t *oscillator);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // SL_CLOCK_MANAGER_HAL_H
|
||||
@@ -0,0 +1,111 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief Clock Manager Init HAL APIs.
|
||||
*******************************************************************************
|
||||
* # License
|
||||
* <b>Copyright 2023 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_CLOCK_MANAGER_INIT_HAL_H
|
||||
#define SL_CLOCK_MANAGER_INIT_HAL_H
|
||||
|
||||
#include "sl_status.h"
|
||||
#include "sl_clock_manager_tree_config.h"
|
||||
#include "sl_clock_manager_oscillator_config.h"
|
||||
#include "em_device.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
******************************** MACROS ************************************
|
||||
******************************************************************************/
|
||||
|
||||
#if (SL_CLOCK_MANAGER_DEFAULT_HF_CLOCK_SOURCE == SL_CLOCK_MANAGER_DEFAULT_HF_CLOCK_SOURCE_HFRCODPLL)
|
||||
#define SL_CLOCK_MANAGER_DEFAULT_HF_CLOCK_SOURCE_CONCATENATION _HFRCODPLL
|
||||
#elif (SL_CLOCK_MANAGER_DEFAULT_HF_CLOCK_SOURCE == SL_CLOCK_MANAGER_DEFAULT_HF_CLOCK_SOURCE_HFXO)
|
||||
#define SL_CLOCK_MANAGER_DEFAULT_HF_CLOCK_SOURCE_CONCATENATION _HFXO
|
||||
#elif (SL_CLOCK_MANAGER_DEFAULT_HF_CLOCK_SOURCE == SL_CLOCK_MANAGER_DEFAULT_HF_CLOCK_SOURCE_FSRCO)
|
||||
#define SL_CLOCK_MANAGER_DEFAULT_HF_CLOCK_SOURCE_CONCATENATION _FSRCO
|
||||
#else
|
||||
#error "SL_CLOCK_MANAGER_DEFAULT_HF_CLOCK_SOURCE configuration value is invalid."
|
||||
#endif
|
||||
|
||||
#if (SL_CLOCK_MANAGER_DEFAULT_LF_CLOCK_SOURCE == SL_CLOCK_MANAGER_DEFAULT_LF_CLOCK_SOURCE_LFRCO)
|
||||
#define SL_CLOCK_MANAGER_DEFAULT_LF_CLOCK_SOURCE_CONCATENATION _LFRCO
|
||||
#elif (SL_CLOCK_MANAGER_DEFAULT_LF_CLOCK_SOURCE == SL_CLOCK_MANAGER_DEFAULT_LF_CLOCK_SOURCE_LFXO)
|
||||
#define SL_CLOCK_MANAGER_DEFAULT_LF_CLOCK_SOURCE_CONCATENATION _LFXO
|
||||
#elif (SL_CLOCK_MANAGER_DEFAULT_LF_CLOCK_SOURCE == SL_CLOCK_MANAGER_DEFAULT_LF_CLOCK_SOURCE_ULFRCO)
|
||||
#define SL_CLOCK_MANAGER_DEFAULT_LF_CLOCK_SOURCE_CONCATENATION _ULFRCO
|
||||
#else
|
||||
#error "SL_CLOCK_MANAGER_DEFAULT_LF_CLOCK_SOURCE configuration value is invalid."
|
||||
#endif
|
||||
|
||||
#define CLOCK_MANAGER_CLOCK_SELECT_SET(clock_branch, clock_source) \
|
||||
do { \
|
||||
CMU->clock_branch##CTRL = (CMU->clock_branch##CTRL & ~_CMU_##clock_branch##CTRL_CLKSEL_MASK) \
|
||||
| clock_source; \
|
||||
} while (0)
|
||||
|
||||
#define CLOCK_MANAGER_GET_DEFAULT_CLOCK_SOURCE_NX(clock_branch, clock_source) CMU_##clock_branch##CTRL_CLKSEL##clock_source
|
||||
#define CLOCK_MANAGER_GET_DEFAULT_CLOCK_SOURCE(clock_branch, clock_source) CLOCK_MANAGER_GET_DEFAULT_CLOCK_SOURCE_NX(clock_branch, clock_source)
|
||||
|
||||
#if !defined(SLI_CLOCK_MANAGER_RUNTIME_CONFIGURATION)
|
||||
#define SLI_CLOCK_MANAGER_HFXO_MODE SL_CLOCK_MANAGER_HFXO_MODE
|
||||
#define SLI_CLOCK_MANAGER_HFRCO_BAND SL_CLOCK_MANAGER_HFRCO_BAND
|
||||
#endif // #if !defined(SLI_CLOCK_MANAGER_RUNTIME_CONFIGURATION)
|
||||
|
||||
#if defined(SL_CLOCK_MANAGER_SOCPLL_EN) && (SL_CLOCK_MANAGER_SOCPLL_EN == 1)
|
||||
#if defined(SL_CLOCK_MANAGER_SOCPLL_ADVANCED_SETTINGS) && (SL_CLOCK_MANAGER_SOCPLL_ADVANCED_SETTINGS == 0)
|
||||
#if defined(SL_CATALOG_RAIL_LIB_PRESENT) || (defined(SL_CLOCK_MANAGER_HFXO_EN) && (SL_CLOCK_MANAGER_HFXO_EN == 1))
|
||||
#define SL_CLOCK_MANAGER_SOCPLL_REFCLK SOCPLL_CTRL_REFCLKSEL_REF_HFXO
|
||||
#define SL_CLOCK_MANAGER_SOCPLL_REFCLK_FREQ SL_CLOCK_MANAGER_HFXO_FREQ
|
||||
#else
|
||||
#define SL_CLOCK_MANAGER_SOCPLL_REFCLK SOCPLL_CTRL_REFCLKSEL_REF_HFRCO
|
||||
#define SL_CLOCK_MANAGER_SOCPLL_REFCLK_FREQ SL_CLOCK_MANAGER_HFRCO_BAND
|
||||
#endif
|
||||
#define SL_CLOCK_MANAGER_SOCPLL_FRACTIONAL_EN 1
|
||||
// SOCPLL Formula: SOCPLL_FREQ = REFCLK_FREQ * (DIVN+2 + DIVF/1024) / 6
|
||||
// SL_CLOCK_MANAGER_SOCPLL_DIVN is rounded down and SL_CLOCK_MANAGER_SOCPLL_DIVF is rounded to the closest integer.
|
||||
#define SL_CLOCK_MANAGER_SOCPLL_DIVN (6ULL * SL_CLOCK_MANAGER_SOCPLL_FREQ / SL_CLOCK_MANAGER_SOCPLL_REFCLK_FREQ - 2ULL)
|
||||
#define SL_CLOCK_MANAGER_SOCPLL_DIVF ((6ULL * 1024ULL * SL_CLOCK_MANAGER_SOCPLL_FREQ + SL_CLOCK_MANAGER_SOCPLL_REFCLK_FREQ / 2ULL) / SL_CLOCK_MANAGER_SOCPLL_REFCLK_FREQ - 1024ULL * (SL_CLOCK_MANAGER_SOCPLL_DIVN + 2ULL))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
****************************** PROTOTYPES **********************************
|
||||
******************************************************************************/
|
||||
|
||||
/***************************************************************************//**
|
||||
* Initializes Oscillators and Clock branches.
|
||||
******************************************************************************/
|
||||
sl_status_t sli_clock_manager_hal_init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // SL_CLOCK_MANAGER_INIT_HAL_H
|
||||
88
Libs/platform/service/device_init/inc/sl_device_init_dcdc.h
Normal file
88
Libs/platform/service/device_init/inc/sl_device_init_dcdc.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief Device initialization for DC/DC converter.
|
||||
*******************************************************************************
|
||||
* # 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_DEVICE_INIT_DCDC_H
|
||||
#define SL_DEVICE_INIT_DCDC_H
|
||||
|
||||
#include "sl_status.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @addtogroup device_init
|
||||
* @{
|
||||
* @addtogroup device_init_dcdc DCDC Initialization
|
||||
* @brief Initialize the DC-DC converter.
|
||||
* @details
|
||||
* Configures the DC-DC converter. If the DC-DC converter is not to be
|
||||
* used, the configuration option `SL_DEVICE_INIT_DCDC_ENABLE` can be disabled,
|
||||
* and the converter will be powered off. On Series 1 devices, this option
|
||||
* should only be used when DVDD is externally powered.
|
||||
*
|
||||
* To enable the bypass switch and short the DC-DC converter input to
|
||||
* the DC-DC output, set the configuration option `SL_DEVICE_INIT_DCDC_BYPASS`.
|
||||
*
|
||||
* See **AN0948 Power Configurations and DC-DC** for further details about DC-DC
|
||||
* converter configuration and operation.
|
||||
*
|
||||
* - Series 1: [AN0948](https://www.silabs.com/documents/public/application-notes/an0948-power-configurations-and-dcdc.pdf)
|
||||
* - Series 2: [AN0948.2](https://www.silabs.com/documents/public/application-notes/an0948.2-efr32-series-2-power-configurations-and-dcdc.pdf)
|
||||
* @{
|
||||
*/
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Defines
|
||||
|
||||
/// @brief DC/DC Converter Type
|
||||
#define SL_DEVICE_INIT_DCDC_TYPE_BUCK 0 ///< Buck Type
|
||||
#define SL_DEVICE_INIT_DCDC_TYPE_BOOST 1 ///< Boost Type
|
||||
|
||||
/**
|
||||
* Initialize DCDC
|
||||
*
|
||||
* @details
|
||||
* Configure and start the DCDC
|
||||
*
|
||||
* @return Status code
|
||||
* @retval SL_STATUS_OK DC-DC converter initialized successfully
|
||||
*/
|
||||
sl_status_t sl_device_init_dcdc(void);
|
||||
|
||||
/**
|
||||
* @} device_init_dcdc
|
||||
* @} device_init
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // SL_DEVICE_INIT_DCDC_H
|
||||
@@ -0,0 +1,60 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief Device initialization for DC/DC converter.
|
||||
*******************************************************************************
|
||||
* # 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_device_init_dcdc.h"
|
||||
#include "sl_device_init_dcdc_config.h"
|
||||
|
||||
#include "em_emu.h"
|
||||
|
||||
sl_status_t sl_device_init_dcdc(void)
|
||||
{
|
||||
#if !defined(SL_DEVICE_INIT_DCDC_TYPE) || (defined(SL_DEVICE_INIT_DCDC_TYPE) && (SL_DEVICE_INIT_DCDC_TYPE == SL_DEVICE_INIT_DCDC_TYPE_BUCK))
|
||||
#if SL_DEVICE_INIT_DCDC_ENABLE
|
||||
EMU_DCDCInit_TypeDef dcdcInit = EMU_DCDCINIT_DEFAULT;
|
||||
#if SL_DEVICE_INIT_DCDC_BYPASS
|
||||
dcdcInit.mode = emuDcdcMode_Bypass;
|
||||
#endif
|
||||
EMU_DCDCInit(&dcdcInit);
|
||||
#if SL_DEVICE_INIT_DCDC_PFMX_IPKVAL_OVERRIDE
|
||||
EMU_DCDCSetPFMXModePeakCurrent(SL_DEVICE_INIT_DCDC_PFMX_IPKVAL);
|
||||
#endif
|
||||
#else // SL_DEVICE_INIT_DCDC_ENABLE
|
||||
EMU_DCDCPowerOff();
|
||||
#endif // SL_DEVICE_INIT_DCDC_ENABLE
|
||||
#else // SL_DEVICE_INIT_DCDC_TYPE
|
||||
#if SL_DEVICE_INIT_DCDC_ENABLE
|
||||
EMU_DCDCBoostInit_TypeDef dcdcBoostInit = EMU_DCDCBOOSTINIT_DEFAULT;
|
||||
#if defined(_DCDC_CTRL_DVDDBSTPRG_MASK)
|
||||
dcdcBoostInit.outputVoltage = SL_DEVICE_INIT_DCDC_BOOST_OUTPUT;
|
||||
#endif
|
||||
EMU_DCDCBoostInit(&dcdcBoostInit);
|
||||
#endif
|
||||
#endif //SL_DEVICE_INIT_DCDC_TYPE
|
||||
return SL_STATUS_OK;
|
||||
}
|
||||
@@ -0,0 +1,339 @@
|
||||
/**************************************************************************//**
|
||||
* @file
|
||||
* @brief Device Manager Clock Definition
|
||||
******************************************************************************
|
||||
* # 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 "em_device.h"
|
||||
#include "sl_device_clock.h"
|
||||
|
||||
/***************************************************************************//**
|
||||
* @addtogroup device_clock Device Manager Clock
|
||||
* @{
|
||||
******************************************************************************/
|
||||
|
||||
#if defined(_CMU_CLKEN1_ACMP0_SHIFT)
|
||||
// Define ACMP0 peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_ACMP0_VALUE = (BUS_CLOCK_CLKEN1 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN1_ACMP0_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN1_ACMP1_SHIFT)
|
||||
// Define ACMP1 peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_ACMP1_VALUE = (BUS_CLOCK_CLKEN1 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN1_ACMP1_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN1_AGC_SHIFT)
|
||||
// Define AGC peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_AGC_VALUE = (BUS_CLOCK_CLKEN1 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN1_AGC_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN0_AMUXCP0_SHIFT)
|
||||
// Define AMUXCP0 peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_AMUXCP0_VALUE = (BUS_CLOCK_CLKEN0 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN0_AMUXCP0_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN1_BUFC_SHIFT)
|
||||
// Define BUFC peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_BUFC_VALUE = (BUS_CLOCK_CLKEN1 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN1_BUFC_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN0_BURAM_SHIFT)
|
||||
// Define BURAM peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_BURAM_VALUE = (BUS_CLOCK_CLKEN0 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN0_BURAM_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN0_BURTC_SHIFT)
|
||||
// Define BURTC peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_BURTC_VALUE = (BUS_CLOCK_CLKEN0 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN0_BURTC_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN0_DCDC_SHIFT)
|
||||
// Define DCDC peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_DCDC_VALUE = (BUS_CLOCK_CLKEN0 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN0_DCDC_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN1_DMEM_SHIFT)
|
||||
// Define DMEM peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_DMEM_VALUE = (BUS_CLOCK_CLKEN1 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN1_DMEM_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN0_DPLL0_SHIFT)
|
||||
// Define DPLL0 peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_DPLL0_VALUE = (BUS_CLOCK_CLKEN0 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN0_DPLL0_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN1_ECAIFADC_SHIFT)
|
||||
// Define ECAIFADC peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_ECAIFADC_VALUE = (BUS_CLOCK_CLKEN1 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN1_ECAIFADC_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN1_EUSART0_SHIFT)
|
||||
// Define EUSART0 peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_EUSART0_VALUE = (BUS_CLOCK_CLKEN1 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN1_EUSART0_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN1_EUSART1_SHIFT)
|
||||
// Define EUSART1 peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_EUSART1_VALUE = (BUS_CLOCK_CLKEN1 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN1_EUSART1_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN1_FRC_SHIFT)
|
||||
// Define FRC peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_FRC_VALUE = (BUS_CLOCK_CLKEN1 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN1_FRC_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN0_FSRCO_SHIFT)
|
||||
// Define FSRCO peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_FSRCO_VALUE = (BUS_CLOCK_CLKEN0 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN0_FSRCO_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN0_GPCRC_SHIFT)
|
||||
// Define GPCRC0 peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_GPCRC0_VALUE = (BUS_CLOCK_CLKEN0 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN0_GPCRC_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN0_GPIO_SHIFT)
|
||||
// Define GPIO peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_GPIO_VALUE = (BUS_CLOCK_CLKEN0 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN0_GPIO_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN0_HFRCO0_SHIFT)
|
||||
// Define HFRCO0 peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_HFRCO0_VALUE = (BUS_CLOCK_CLKEN0 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN0_HFRCO0_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN0_HFRCOEM23_SHIFT)
|
||||
// Define HFRCOEM23 peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_HFRCOEM23_VALUE = (BUS_CLOCK_CLKEN0 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN0_HFRCOEM23_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN0_HFXO0_SHIFT)
|
||||
// Define HFXO0 peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_HFXO0_VALUE = (BUS_CLOCK_CLKEN0 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN0_HFXO0_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN1_HOSTMAILBOX_SHIFT)
|
||||
// Define HOSTMAILBOX peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_HOSTMAILBOX_VALUE = (BUS_CLOCK_CLKEN1 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN1_HOSTMAILBOX_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN0_I2C0_SHIFT)
|
||||
// Define I2C0 peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_I2C0_VALUE = (BUS_CLOCK_CLKEN0 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN0_I2C0_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN0_I2C1_SHIFT)
|
||||
// Define I2C1 peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_I2C1_VALUE = (BUS_CLOCK_CLKEN0 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN0_I2C1_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN0_IADC0_SHIFT)
|
||||
// Define IADC0 peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_IADC0_VALUE = (BUS_CLOCK_CLKEN0 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN0_IADC0_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN1_ICACHE0_SHIFT)
|
||||
// Define ICACHE0 peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_ICACHE0_VALUE = (BUS_CLOCK_CLKEN1 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN1_ICACHE0_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN1_KEYSCAN_SHIFT)
|
||||
// Define KEYSCAN peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_KEYSCAN_VALUE = (BUS_CLOCK_CLKEN1 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN1_KEYSCAN_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN0_LDMA_SHIFT)
|
||||
// Define LDMA0 peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_LDMA0_VALUE = (BUS_CLOCK_CLKEN0 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN0_LDMA_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN0_LDMAXBAR_SHIFT)
|
||||
// Define LDMAXBAR0 peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_LDMAXBAR0_VALUE = (BUS_CLOCK_CLKEN0 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN0_LDMAXBAR_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN0_LETIMER0_SHIFT)
|
||||
// Define LETIMER0 peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_LETIMER0_VALUE = (BUS_CLOCK_CLKEN0 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN0_LETIMER0_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN0_LFRCO_SHIFT)
|
||||
// Define LFRCO peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_LFRCO_VALUE = (BUS_CLOCK_CLKEN0 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN0_LFRCO_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN0_LFXO_SHIFT)
|
||||
// Define LFXO peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_LFXO_VALUE = (BUS_CLOCK_CLKEN0 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN0_LFXO_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN1_MODEM_SHIFT)
|
||||
// Define MODEM peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_MODEM_VALUE = (BUS_CLOCK_CLKEN1 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN1_MODEM_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN1_MSC_SHIFT)
|
||||
// Define MSC peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_MSC_VALUE = (BUS_CLOCK_CLKEN1 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN1_MSC_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN1_MVP_SHIFT)
|
||||
// Define MVP peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_MVP_VALUE = (BUS_CLOCK_CLKEN1 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN1_MVP_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN1_PCNT0_SHIFT)
|
||||
// Define PCNT0 peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_PCNT0_VALUE = (BUS_CLOCK_CLKEN1 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN1_PCNT0_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN1_PROTIMER_SHIFT)
|
||||
// Define PROTIMER peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_PROTIMER_VALUE = (BUS_CLOCK_CLKEN1 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN1_PROTIMER_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN0_PRS_SHIFT)
|
||||
// Define PRS peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_PRS_VALUE = (BUS_CLOCK_CLKEN0 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN0_PRS_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN1_RAC_SHIFT)
|
||||
// Define RAC peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_RAC_VALUE = (BUS_CLOCK_CLKEN1 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN1_RAC_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN0_RADIOAES_SHIFT)
|
||||
// Define RADIOAES peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_RADIOAES_VALUE = (BUS_CLOCK_CLKEN0 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN0_RADIOAES_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN1_RFCRC_SHIFT)
|
||||
// Define RFCRC peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_RFCRC_VALUE = (BUS_CLOCK_CLKEN1 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN1_RFCRC_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN1_RFECA0_SHIFT)
|
||||
// Define RFECA0 peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_RFECA0_VALUE = (BUS_CLOCK_CLKEN1 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN1_RFECA0_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN1_RFECA1_SHIFT)
|
||||
// Define RFECA1 peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_RFECA1_VALUE = (BUS_CLOCK_CLKEN1 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN1_RFECA1_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN1_RFMAILBOX_SHIFT)
|
||||
// Define RFMAILBOX peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_RFMAILBOX_VALUE = (BUS_CLOCK_CLKEN1 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN1_RFMAILBOX_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN1_RFSCRATCHPAD_SHIFT)
|
||||
// Define RFSCRATCHPAD peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_RFSCRATCHPAD_VALUE = (BUS_CLOCK_CLKEN1 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN1_RFSCRATCHPAD_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN1_SEMAILBOXHOST_SHIFT)
|
||||
// Define SEMAILBOX peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_SEMAILBOX_VALUE = (BUS_CLOCK_CLKEN1 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN1_SEMAILBOXHOST_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN1_SMU_SHIFT)
|
||||
// Define SMU peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_SMU_VALUE = (BUS_CLOCK_CLKEN1 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN1_SMU_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN1_SYNTH_SHIFT)
|
||||
// Define SYNTH peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_SYNTH_VALUE = (BUS_CLOCK_CLKEN1 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN1_SYNTH_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN0_SYSCFG_SHIFT)
|
||||
// Define SYSCFG peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_SYSCFG_VALUE = (BUS_CLOCK_CLKEN0 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN0_SYSCFG_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN0_SYSRTC0_SHIFT)
|
||||
// Define SYSRTC0 peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_SYSRTC0_VALUE = (BUS_CLOCK_CLKEN0 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN0_SYSRTC0_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN0_TIMER0_SHIFT)
|
||||
// Define TIMER0 peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_TIMER0_VALUE = (BUS_CLOCK_CLKEN0 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN0_TIMER0_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN0_TIMER1_SHIFT)
|
||||
// Define TIMER1 peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_TIMER1_VALUE = (BUS_CLOCK_CLKEN0 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN0_TIMER1_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN0_TIMER2_SHIFT)
|
||||
// Define TIMER2 peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_TIMER2_VALUE = (BUS_CLOCK_CLKEN0 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN0_TIMER2_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN0_TIMER3_SHIFT)
|
||||
// Define TIMER3 peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_TIMER3_VALUE = (BUS_CLOCK_CLKEN0 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN0_TIMER3_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN0_TIMER4_SHIFT)
|
||||
// Define TIMER4 peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_TIMER4_VALUE = (BUS_CLOCK_CLKEN0 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN0_TIMER4_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN0_ULFRCO_SHIFT)
|
||||
// Define ULFRCO peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_ULFRCO_VALUE = (BUS_CLOCK_CLKEN0 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN0_ULFRCO_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN0_USART0_SHIFT)
|
||||
// Define USART0 peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_USART0_VALUE = (BUS_CLOCK_CLKEN0 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN0_USART0_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN1_VDAC0_SHIFT)
|
||||
// Define VDAC0 peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_VDAC0_VALUE = (BUS_CLOCK_CLKEN1 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN1_VDAC0_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN1_VDAC1_SHIFT)
|
||||
// Define VDAC1 peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_VDAC1_VALUE = (BUS_CLOCK_CLKEN1 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN1_VDAC1_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN0_WDOG0_SHIFT)
|
||||
// Define WDOG0 peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_WDOG0_VALUE = (BUS_CLOCK_CLKEN0 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN0_WDOG0_SHIFT;
|
||||
#endif
|
||||
|
||||
#if defined(_CMU_CLKEN1_WDOG1_SHIFT)
|
||||
// Define WDOG1 peripheral bus clock value.
|
||||
const uint32_t SL_BUS_CLOCK_WDOG1_VALUE = (BUS_CLOCK_CLKEN1 << _BUS_CLOCK_CLKENX_SHIFT) | _CMU_CLKEN1_WDOG1_SHIFT;
|
||||
#endif
|
||||
|
||||
/** @} (end addtogroup device_clock) */
|
||||
@@ -0,0 +1,383 @@
|
||||
/**************************************************************************//**
|
||||
* @file
|
||||
* @brief Device Manager Peripheral Definition
|
||||
******************************************************************************
|
||||
* # 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 "em_device.h"
|
||||
#include "sl_device_peripheral.h"
|
||||
#include "sl_device_clock.h"
|
||||
|
||||
/***************************************************************************//**
|
||||
* @addtogroup device_peripheral Device Abstraction Peripheral
|
||||
* @{
|
||||
******************************************************************************/
|
||||
|
||||
#if defined(ACMP0_BASE)
|
||||
// Define peripheral ACMP0.
|
||||
const sl_peripheral_val_t sl_peripheral_val_acmp0 = { .base = ACMP0_BASE,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_ACMP0 };
|
||||
#endif
|
||||
|
||||
#if defined(ACMP1_BASE)
|
||||
// Define peripheral ACMP1.
|
||||
const sl_peripheral_val_t sl_peripheral_val_acmp1 = { .base = ACMP1_BASE,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_ACMP1 };
|
||||
#endif
|
||||
|
||||
#if defined(BURAM_BASE)
|
||||
// Define peripheral BURAM.
|
||||
const sl_peripheral_val_t sl_peripheral_val_buram = { .base = BURAM_BASE,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_BURAM };
|
||||
#endif
|
||||
|
||||
#if defined(BURTC_BASE)
|
||||
// Define peripheral BURTC.
|
||||
const sl_peripheral_val_t sl_peripheral_val_burtc = { .base = BURTC_BASE,
|
||||
.clk_branch = SL_CLOCK_BRANCH_EM4GRPACLK,
|
||||
.bus_clock = SL_BUS_CLOCK_BURTC };
|
||||
#endif
|
||||
|
||||
#if defined(CMU_BASE)
|
||||
// Define peripheral CMU.
|
||||
const sl_peripheral_val_t sl_peripheral_val_cmu = { .base = CMU_BASE,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
#endif
|
||||
|
||||
#if defined(DCDC_BASE)
|
||||
// Define peripheral DCDC.
|
||||
const sl_peripheral_val_t sl_peripheral_val_dcdc = { .base = DCDC_BASE,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_DCDC };
|
||||
#endif
|
||||
|
||||
#if defined(DMEM_BASE)
|
||||
// Define peripheral DMEM.
|
||||
const sl_peripheral_val_t sl_peripheral_val_dmem = { .base = DMEM_BASE,
|
||||
.clk_branch = SL_CLOCK_BRANCH_PCLK,
|
||||
.bus_clock = SL_BUS_CLOCK_DMEM };
|
||||
#endif
|
||||
|
||||
#if defined(DPLL0_BASE)
|
||||
// Define peripheral DPLL0.
|
||||
const sl_peripheral_val_t sl_peripheral_val_dpll0 = { .base = DPLL0_BASE,
|
||||
.clk_branch = SL_CLOCK_BRANCH_DPLLREFCLK,
|
||||
.bus_clock = SL_BUS_CLOCK_DPLL0 };
|
||||
#endif
|
||||
|
||||
#if defined(EMU_BASE)
|
||||
// Define peripheral EMU.
|
||||
const sl_peripheral_val_t sl_peripheral_val_emu = { .base = EMU_BASE,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
#endif
|
||||
|
||||
#if defined(EUSART0_BASE)
|
||||
// Define peripheral EUSART0.
|
||||
const sl_peripheral_val_t sl_peripheral_val_eusart0 = { .base = EUSART0_BASE,
|
||||
.clk_branch = SL_CLOCK_BRANCH_EUSART0CLK,
|
||||
.bus_clock = SL_BUS_CLOCK_EUSART0 };
|
||||
#endif
|
||||
|
||||
#if defined(EUSART1_BASE)
|
||||
// Define peripheral EUSART1.
|
||||
const sl_peripheral_val_t sl_peripheral_val_eusart1 = { .base = EUSART1_BASE,
|
||||
.clk_branch = SL_CLOCK_BRANCH_EM01GRPCCLK,
|
||||
.bus_clock = SL_BUS_CLOCK_EUSART1 };
|
||||
#endif
|
||||
|
||||
#if defined(FSRCO_BASE)
|
||||
// Define peripheral FSRCO.
|
||||
const sl_peripheral_val_t sl_peripheral_val_fsrco = { .base = FSRCO_BASE,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_FSRCO };
|
||||
#endif
|
||||
|
||||
#if defined(GPCRC_BASE)
|
||||
// Define peripheral GPCRC0.
|
||||
const sl_peripheral_val_t sl_peripheral_val_gpcrc0 = { .base = GPCRC_BASE,
|
||||
.clk_branch = SL_CLOCK_BRANCH_PCLK,
|
||||
.bus_clock = SL_BUS_CLOCK_GPCRC0 };
|
||||
#endif
|
||||
|
||||
#if defined(GPIO_BASE)
|
||||
// Define peripheral GPIO.
|
||||
const sl_peripheral_val_t sl_peripheral_val_gpio = { .base = GPIO_BASE,
|
||||
.clk_branch = SL_CLOCK_BRANCH_PCLK,
|
||||
.bus_clock = SL_BUS_CLOCK_GPIO };
|
||||
#endif
|
||||
|
||||
#if defined(HFRCO0_BASE)
|
||||
// Define peripheral HFRCO0.
|
||||
const sl_peripheral_val_t sl_peripheral_val_hfrco0 = { .base = HFRCO0_BASE,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_HFRCO0 };
|
||||
#endif
|
||||
|
||||
#if defined(HFRCOEM23_BASE)
|
||||
// Define peripheral HFRCOEM23.
|
||||
const sl_peripheral_val_t sl_peripheral_val_hfrcoem23 = { .base = HFRCOEM23_BASE,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_HFRCOEM23 };
|
||||
#endif
|
||||
|
||||
#if defined(HFXO0_BASE)
|
||||
// Define peripheral HFXO0.
|
||||
const sl_peripheral_val_t sl_peripheral_val_hfxo0 = { .base = HFXO0_BASE,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_HFXO0 };
|
||||
#endif
|
||||
|
||||
#if defined(HOSTMAILBOX_BASE)
|
||||
// Define peripheral HOSTMAILBOX.
|
||||
const sl_peripheral_val_t sl_peripheral_val_hostmailbox = { .base = HOSTMAILBOX_BASE,
|
||||
.clk_branch = SL_CLOCK_BRANCH_PCLK,
|
||||
.bus_clock = SL_BUS_CLOCK_HOSTMAILBOX };
|
||||
#endif
|
||||
|
||||
#if defined(I2C0_BASE)
|
||||
// Define peripheral I2C0.
|
||||
const sl_peripheral_val_t sl_peripheral_val_i2c0 = { .base = I2C0_BASE,
|
||||
.clk_branch = SL_CLOCK_BRANCH_LSPCLK,
|
||||
.bus_clock = SL_BUS_CLOCK_I2C0 };
|
||||
#endif
|
||||
|
||||
#if defined(I2C1_BASE)
|
||||
// Define peripheral I2C1.
|
||||
const sl_peripheral_val_t sl_peripheral_val_i2c1 = { .base = I2C1_BASE,
|
||||
.clk_branch = SL_CLOCK_BRANCH_PCLK,
|
||||
.bus_clock = SL_BUS_CLOCK_I2C1 };
|
||||
#endif
|
||||
|
||||
#if defined(IADC0_BASE)
|
||||
// Define peripheral IADC0.
|
||||
const sl_peripheral_val_t sl_peripheral_val_iadc0 = { .base = IADC0_BASE,
|
||||
.clk_branch = SL_CLOCK_BRANCH_IADCCLK,
|
||||
.bus_clock = SL_BUS_CLOCK_IADC0 };
|
||||
#endif
|
||||
|
||||
#if defined(ICACHE0_BASE)
|
||||
// Define peripheral ICACHE0.
|
||||
const sl_peripheral_val_t sl_peripheral_val_icache0 = { .base = ICACHE0_BASE,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_ICACHE0 };
|
||||
#endif
|
||||
|
||||
#if defined(KEYSCAN_BASE)
|
||||
// Define peripheral KEYSCAN.
|
||||
const sl_peripheral_val_t sl_peripheral_val_keyscan = { .base = KEYSCAN_BASE,
|
||||
.clk_branch = SL_CLOCK_BRANCH_EM01GRPACLK,
|
||||
.bus_clock = SL_BUS_CLOCK_KEYSCAN };
|
||||
#endif
|
||||
|
||||
#if defined(LDMA_BASE)
|
||||
// Define peripheral LDMA0.
|
||||
const sl_peripheral_val_t sl_peripheral_val_ldma0 = { .base = LDMA_BASE,
|
||||
.clk_branch = SL_CLOCK_BRANCH_HCLK,
|
||||
.bus_clock = SL_BUS_CLOCK_LDMA0 };
|
||||
#endif
|
||||
|
||||
#if defined(LDMAXBAR_BASE)
|
||||
// Define peripheral LDMAXBAR0.
|
||||
const sl_peripheral_val_t sl_peripheral_val_ldmaxbar0 = { .base = LDMAXBAR_BASE,
|
||||
.clk_branch = SL_CLOCK_BRANCH_PCLK,
|
||||
.bus_clock = SL_BUS_CLOCK_LDMAXBAR0 };
|
||||
#endif
|
||||
|
||||
#if defined(LETIMER0_BASE)
|
||||
// Define peripheral LETIMER0.
|
||||
const sl_peripheral_val_t sl_peripheral_val_letimer0 = { .base = LETIMER0_BASE,
|
||||
.clk_branch = SL_CLOCK_BRANCH_EM23GRPACLK,
|
||||
.bus_clock = SL_BUS_CLOCK_LETIMER0 };
|
||||
#endif
|
||||
|
||||
#if defined(LFRCO_BASE)
|
||||
// Define peripheral LFRCO.
|
||||
const sl_peripheral_val_t sl_peripheral_val_lfrco = { .base = LFRCO_BASE,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_LFRCO };
|
||||
#endif
|
||||
|
||||
#if defined(LFXO_BASE)
|
||||
// Define peripheral LFXO.
|
||||
const sl_peripheral_val_t sl_peripheral_val_lfxo = { .base = LFXO_BASE,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_LFXO };
|
||||
#endif
|
||||
|
||||
#if defined(MSC_BASE)
|
||||
// Define peripheral MSC.
|
||||
const sl_peripheral_val_t sl_peripheral_val_msc = { .base = MSC_BASE,
|
||||
.clk_branch = SL_CLOCK_BRANCH_HCLK,
|
||||
.bus_clock = SL_BUS_CLOCK_MSC };
|
||||
#endif
|
||||
|
||||
#if defined(MVP_BASE)
|
||||
// Define peripheral MVP.
|
||||
const sl_peripheral_val_t sl_peripheral_val_mvp = { .base = MVP_BASE,
|
||||
.clk_branch = SL_CLOCK_BRANCH_HCLK,
|
||||
.bus_clock = SL_BUS_CLOCK_MVP };
|
||||
#endif
|
||||
|
||||
#if defined(PCNT0_BASE)
|
||||
// Define peripheral PCNT0.
|
||||
const sl_peripheral_val_t sl_peripheral_val_pcnt0 = { .base = PCNT0_BASE,
|
||||
.clk_branch = SL_CLOCK_BRANCH_PCNT0CLK,
|
||||
.bus_clock = SL_BUS_CLOCK_PCNT0 };
|
||||
#endif
|
||||
|
||||
#if defined(PRS_BASE)
|
||||
// Define peripheral PRS.
|
||||
const sl_peripheral_val_t sl_peripheral_val_prs = { .base = PRS_BASE,
|
||||
.clk_branch = SL_CLOCK_BRANCH_PCLK,
|
||||
.bus_clock = SL_BUS_CLOCK_PRS };
|
||||
#endif
|
||||
|
||||
#if defined(RADIOAES_BASE)
|
||||
// Define peripheral RADIOAES.
|
||||
const sl_peripheral_val_t sl_peripheral_val_radioaes = { .base = RADIOAES_BASE,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_RADIOAES };
|
||||
#endif
|
||||
|
||||
#if defined(SCRATCHPAD_BASE)
|
||||
// Define peripheral SCRATCHPAD.
|
||||
const sl_peripheral_val_t sl_peripheral_val_scratchpad = { .base = SCRATCHPAD_BASE,
|
||||
.clk_branch = SL_CLOCK_BRANCH_PCLK,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
#endif
|
||||
|
||||
#if defined(SEMAILBOX_HOST_BASE)
|
||||
// Define peripheral SEMAILBOX.
|
||||
const sl_peripheral_val_t sl_peripheral_val_semailbox = { .base = SEMAILBOX_HOST_BASE,
|
||||
.clk_branch = SL_CLOCK_BRANCH_HCLK,
|
||||
.bus_clock = SL_BUS_CLOCK_SEMAILBOX };
|
||||
#endif
|
||||
|
||||
#if defined(SMU_BASE)
|
||||
// Define peripheral SMU.
|
||||
const sl_peripheral_val_t sl_peripheral_val_smu = { .base = SMU_BASE,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_SMU };
|
||||
#endif
|
||||
|
||||
#if defined(SYSCFG_BASE)
|
||||
// Define peripheral SYSCFG.
|
||||
const sl_peripheral_val_t sl_peripheral_val_syscfg = { .base = SYSCFG_BASE,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_SYSCFG };
|
||||
#endif
|
||||
|
||||
#if defined(SYSRTC0_BASE)
|
||||
// Define peripheral SYSRTC0.
|
||||
const sl_peripheral_val_t sl_peripheral_val_sysrtc0 = { .base = SYSRTC0_BASE,
|
||||
.clk_branch = SL_CLOCK_BRANCH_SYSRTCCLK,
|
||||
.bus_clock = SL_BUS_CLOCK_SYSRTC0 };
|
||||
#endif
|
||||
|
||||
#if defined(TIMER0_BASE)
|
||||
// Define peripheral TIMER0.
|
||||
const sl_peripheral_val_t sl_peripheral_val_timer0 = { .base = TIMER0_BASE,
|
||||
.clk_branch = SL_CLOCK_BRANCH_EM01GRPACLK,
|
||||
.bus_clock = SL_BUS_CLOCK_TIMER0 };
|
||||
#endif
|
||||
|
||||
#if defined(TIMER1_BASE)
|
||||
// Define peripheral TIMER1.
|
||||
const sl_peripheral_val_t sl_peripheral_val_timer1 = { .base = TIMER1_BASE,
|
||||
.clk_branch = SL_CLOCK_BRANCH_EM01GRPACLK,
|
||||
.bus_clock = SL_BUS_CLOCK_TIMER1 };
|
||||
#endif
|
||||
|
||||
#if defined(TIMER2_BASE)
|
||||
// Define peripheral TIMER2.
|
||||
const sl_peripheral_val_t sl_peripheral_val_timer2 = { .base = TIMER2_BASE,
|
||||
.clk_branch = SL_CLOCK_BRANCH_EM01GRPACLK,
|
||||
.bus_clock = SL_BUS_CLOCK_TIMER2 };
|
||||
#endif
|
||||
|
||||
#if defined(TIMER3_BASE)
|
||||
// Define peripheral TIMER3.
|
||||
const sl_peripheral_val_t sl_peripheral_val_timer3 = { .base = TIMER3_BASE,
|
||||
.clk_branch = SL_CLOCK_BRANCH_EM01GRPACLK,
|
||||
.bus_clock = SL_BUS_CLOCK_TIMER3 };
|
||||
#endif
|
||||
|
||||
#if defined(TIMER4_BASE)
|
||||
// Define peripheral TIMER4.
|
||||
const sl_peripheral_val_t sl_peripheral_val_timer4 = { .base = TIMER4_BASE,
|
||||
.clk_branch = SL_CLOCK_BRANCH_EM01GRPACLK,
|
||||
.bus_clock = SL_BUS_CLOCK_TIMER4 };
|
||||
#endif
|
||||
|
||||
#if defined(ULFRCO_BASE)
|
||||
// Define peripheral ULFRCO.
|
||||
const sl_peripheral_val_t sl_peripheral_val_ulfrco = { .base = ULFRCO_BASE,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_ULFRCO };
|
||||
#endif
|
||||
|
||||
#if defined(USART0_BASE)
|
||||
// Define peripheral USART0.
|
||||
const sl_peripheral_val_t sl_peripheral_val_usart0 = { .base = USART0_BASE,
|
||||
.clk_branch = SL_CLOCK_BRANCH_PCLK,
|
||||
.bus_clock = SL_BUS_CLOCK_USART0 };
|
||||
#endif
|
||||
|
||||
#if defined(VDAC0_BASE)
|
||||
// Define peripheral VDAC0.
|
||||
const sl_peripheral_val_t sl_peripheral_val_vdac0 = { .base = VDAC0_BASE,
|
||||
.clk_branch = SL_CLOCK_BRANCH_VDAC0CLK,
|
||||
.bus_clock = SL_BUS_CLOCK_VDAC0 };
|
||||
#endif
|
||||
|
||||
#if defined(VDAC1_BASE)
|
||||
// Define peripheral VDAC1.
|
||||
const sl_peripheral_val_t sl_peripheral_val_vdac1 = { .base = VDAC1_BASE,
|
||||
.clk_branch = SL_CLOCK_BRANCH_VDAC1CLK,
|
||||
.bus_clock = SL_BUS_CLOCK_VDAC1 };
|
||||
#endif
|
||||
|
||||
#if defined(WDOG0_BASE)
|
||||
// Define peripheral WDOG0.
|
||||
const sl_peripheral_val_t sl_peripheral_val_wdog0 = { .base = WDOG0_BASE,
|
||||
.clk_branch = SL_CLOCK_BRANCH_WDOG0CLK,
|
||||
.bus_clock = SL_BUS_CLOCK_WDOG0 };
|
||||
#endif
|
||||
|
||||
#if defined(WDOG1_BASE)
|
||||
// Define peripheral WDOG1.
|
||||
const sl_peripheral_val_t sl_peripheral_val_wdog1 = { .base = WDOG1_BASE,
|
||||
.clk_branch = SL_CLOCK_BRANCH_WDOG1CLK,
|
||||
.bus_clock = SL_BUS_CLOCK_WDOG1 };
|
||||
#endif
|
||||
|
||||
/** @} (end addtogroup device_peripheral) */
|
||||
806
Libs/platform/service/device_manager/inc/sl_device_clock.h
Normal file
806
Libs/platform/service/device_manager/inc/sl_device_clock.h
Normal file
@@ -0,0 +1,806 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief Device Manager Clocks.
|
||||
*******************************************************************************
|
||||
* # 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.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef SL_DEVICE_CLOCK_H
|
||||
#define SL_DEVICE_CLOCK_H
|
||||
|
||||
#include "sl_enum.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(DEVICE_CLOCK_INTERNAL_PRESENT)
|
||||
#include "sli_device_clock_internal.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/***************************************************************************//**
|
||||
* @addtogroup device_clock Device Manager Clock
|
||||
* @details
|
||||
* ## Overview
|
||||
*
|
||||
* The Device Manager Clock module defines the different oscillators,
|
||||
* clock branches and bus clock values that exist across all Silicon Labs
|
||||
* devices.
|
||||
*
|
||||
* @{
|
||||
******************************************************************************/
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// ENUMS
|
||||
|
||||
/// Oscillators
|
||||
SL_ENUM(sl_oscillator_t) {
|
||||
SL_OSCILLATOR_FSRCO, ///< FSRCO Oscillator
|
||||
SL_OSCILLATOR_HFRCODPLL, ///< HFRCODPLL Oscillator
|
||||
SL_OSCILLATOR_HFXO, ///< HFXO Oscillator
|
||||
SL_OSCILLATOR_HFRCOEM23, ///< HFRCOEM23 Oscillator
|
||||
SL_OSCILLATOR_RFFPLL, ///< RFFPLL Oscillator
|
||||
SL_OSCILLATOR_USBPLL, ///< USBPLL Oscillator
|
||||
SL_OSCILLATOR_SOCPLL, ///< SOCPLL Oscillator
|
||||
SL_OSCILLATOR_LFXO, ///< LFXO Oscillator
|
||||
SL_OSCILLATOR_LFRCO, ///< LFRCO Oscillator
|
||||
SL_OSCILLATOR_ULFRCO, ///< ULFRCO Oscillator
|
||||
SL_OSCILLATOR_CLKIN0, ///< CLKIN0 Oscillator
|
||||
SL_OSCILLATOR_FLPLL ///< FLPLL Oscillator
|
||||
};
|
||||
|
||||
/// Clock Branches
|
||||
SL_ENUM(sl_clock_branch_t) {
|
||||
SL_CLOCK_BRANCH_SYSCLK, ///< SYSCLK Clock Branch
|
||||
SL_CLOCK_BRANCH_HCLK, ///< HCLK Clock Branch
|
||||
SL_CLOCK_BRANCH_HCLKRADIO, ///< HCLK Radio Clock Branch
|
||||
SL_CLOCK_BRANCH_PCLK, ///< PCLK Clock Branch
|
||||
SL_CLOCK_BRANCH_LSPCLK, ///< LSPCLK Clock Branch
|
||||
SL_CLOCK_BRANCH_TRACECLK, ///< TRACECLK Clock Branch
|
||||
SL_CLOCK_BRANCH_ADCCLK, ///< ADCCLK Clock Branch
|
||||
SL_CLOCK_BRANCH_EXPORTCLK, ///< EXPORTCLK Clock Branch
|
||||
SL_CLOCK_BRANCH_EM01GRPACLK, ///< EM01GRPACLK Clock Branch
|
||||
SL_CLOCK_BRANCH_EM01GRPBCLK, ///< EM01GRPBCLK Clock Branch
|
||||
SL_CLOCK_BRANCH_EM01GRPCCLK, ///< EM01GRPCCLK Clock Branch
|
||||
SL_CLOCK_BRANCH_EM01GRPDCLK, ///< EM01GRPDCLK Clock Branch
|
||||
SL_CLOCK_BRANCH_EM23GRPACLK, ///< EM23GRPACLK Clock Branch
|
||||
SL_CLOCK_BRANCH_EM4GRPACLK, ///< EM4GRPACLK Clock Branch
|
||||
SL_CLOCK_BRANCH_QSPISYSCLK, ///< QSPISYSCLK Clock Branch
|
||||
SL_CLOCK_BRANCH_IADCCLK, ///< IADCCLK Clock Branch
|
||||
SL_CLOCK_BRANCH_WDOG0CLK, ///< WDOG0CLK Clock Branch
|
||||
SL_CLOCK_BRANCH_WDOG1CLK, ///< WDOG1CLK Clock Branch
|
||||
SL_CLOCK_BRANCH_RTCCCLK, ///< RTCCCLK Clock Branch
|
||||
SL_CLOCK_BRANCH_SYSRTCCLK, ///< SYSRTCCLK Clock Branch
|
||||
SL_CLOCK_BRANCH_EUART0CLK, ///< EUART0CLK Clock Branch
|
||||
SL_CLOCK_BRANCH_EUSART0CLK, ///< EUSART0CLK Clock Branch
|
||||
SL_CLOCK_BRANCH_DPLLREFCLK, ///< DPLLREFCLK Clock Branch
|
||||
SL_CLOCK_BRANCH_I2C0CLK, ///< I2C0CLK Clock Branch
|
||||
SL_CLOCK_BRANCH_LCDCLK, ///< LCDCLK Clock Branch
|
||||
SL_CLOCK_BRANCH_PIXELRZCLK, ///< PIXELRZCLK Clock Branch
|
||||
SL_CLOCK_BRANCH_PCNT0CLK, ///< PCNT0CLK Clock Branch
|
||||
SL_CLOCK_BRANCH_PRORTCCLK, ///< PCNT0CLK Clock Branch
|
||||
SL_CLOCK_BRANCH_SYSTICKCLK, ///< SYSTICKCLK Clock Branch
|
||||
SL_CLOCK_BRANCH_LESENSEHFCLK, ///< LESENSEHFCLK Clock Branch
|
||||
SL_CLOCK_BRANCH_VDAC0CLK, ///< VDAC0CLK Clock Branch
|
||||
SL_CLOCK_BRANCH_VDAC1CLK, ///< VDAC1CLK Clock Branch
|
||||
SL_CLOCK_BRANCH_USB0CLK, ///< USB0CLK Clock Branch
|
||||
SL_CLOCK_BRANCH_FLPLLREFCLK, ///< FLPLLREFCLK Clock Branch
|
||||
SL_CLOCK_BRANCH_INVALID ///< INVALID Clock Branch
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// DEFINES
|
||||
|
||||
/// @cond DO_NOT_INCLUDE_WITH_DOXYGEN
|
||||
|
||||
// CLKEN bitfield shift in bus clock value.
|
||||
#define _BUS_CLOCK_CLKEN_BIT_SHIFT 0
|
||||
|
||||
// CLKEN bitfield mask in bus clock value.
|
||||
#define _BUS_CLOCK_CLKEN_BIT_MASK 0x3FUL
|
||||
|
||||
// CLKENx register number shift in bus clock value.
|
||||
#define _BUS_CLOCK_CLKENX_SHIFT 6
|
||||
|
||||
// CLKENx register number mask in bus clock value.
|
||||
#define _BUS_CLOCK_CLKENX_MASK 0x1C0UL
|
||||
|
||||
// CLKEN0 value in bus clock.
|
||||
#define BUS_CLOCK_CLKEN0 0x0UL
|
||||
|
||||
// CLKEN1 value in bus clock.
|
||||
#define BUS_CLOCK_CLKEN1 0x1UL
|
||||
|
||||
// CLKEN2 value in bus clock.
|
||||
#define BUS_CLOCK_CLKEN2 0x2UL
|
||||
|
||||
// CLKENHV value in bus clock.
|
||||
#define BUS_CLOCK_CLKENHV 0x3UL
|
||||
|
||||
/// @endcond
|
||||
|
||||
/***************************************************************************//**
|
||||
* @name Bus Clock Defines
|
||||
* Those defines can be used as constant of type sl_bus_clock_t and thus can
|
||||
* be used as argument for function sl_clock_manager_enable_bus_clock() and
|
||||
* sl_clock_manager_disable_bus_clock() in @ref clock_manager.
|
||||
* The values of those defines are device specific.
|
||||
* @{
|
||||
******************************************************************************/
|
||||
|
||||
/// Define for INVALID peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_INVALID (0)
|
||||
|
||||
/// Define for ACMP0 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_ACMP0 (&SL_BUS_CLOCK_ACMP0_VALUE)
|
||||
|
||||
/// Define for ACMP1 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_ACMP1 (&SL_BUS_CLOCK_ACMP1_VALUE)
|
||||
|
||||
/// Define for ADC0 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_ADC0 (&SL_BUS_CLOCK_ADC0_VALUE)
|
||||
|
||||
/// Define for AGC peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_AGC (&SL_BUS_CLOCK_AGC_VALUE)
|
||||
|
||||
/// Define for AMUXCP0 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_AMUXCP0 (&SL_BUS_CLOCK_AMUXCP0_VALUE)
|
||||
|
||||
/// Define for BUFC peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_BUFC (&SL_BUS_CLOCK_BUFC_VALUE)
|
||||
|
||||
/// Define for BURAM peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_BURAM (&SL_BUS_CLOCK_BURAM_VALUE)
|
||||
|
||||
/// Define for BURTC peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_BURTC (&SL_BUS_CLOCK_BURTC_VALUE)
|
||||
|
||||
/// Define for CRYPTOACC peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_CRYPTOACC (&SL_BUS_CLOCK_CRYPTOACC_VALUE)
|
||||
|
||||
/// Define for DCDC peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_DCDC (&SL_BUS_CLOCK_DCDC_VALUE)
|
||||
|
||||
/// Define for DEVINFO peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_DEVINFO (&SL_BUS_CLOCK_DEVINFO_VALUE)
|
||||
|
||||
/// Define for DMEM peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_DMEM (&SL_BUS_CLOCK_DMEM_VALUE)
|
||||
|
||||
/// Define for DPLL0 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_DPLL0 (&SL_BUS_CLOCK_DPLL0_VALUE)
|
||||
|
||||
/// Define for ECAIFADC peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_ECAIFADC (&SL_BUS_CLOCK_ECAIFADC_VALUE)
|
||||
|
||||
/// Define for ETAMPDET peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_ETAMPDET (&SL_BUS_CLOCK_ETAMPDET_VALUE)
|
||||
|
||||
/// Define for EUART0 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_EUART0 (&SL_BUS_CLOCK_EUART0_VALUE)
|
||||
|
||||
/// Define for EUSART0 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_EUSART0 (&SL_BUS_CLOCK_EUSART0_VALUE)
|
||||
|
||||
/// Define for EUSART1 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_EUSART1 (&SL_BUS_CLOCK_EUSART1_VALUE)
|
||||
|
||||
/// Define for EUSART2 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_EUSART2 (&SL_BUS_CLOCK_EUSART2_VALUE)
|
||||
|
||||
/// Define for EUSART3 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_EUSART3 (&SL_BUS_CLOCK_EUSART3_VALUE)
|
||||
|
||||
/// Define for EUSART4 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_EUSART4 (&SL_BUS_CLOCK_EUSART4_VALUE)
|
||||
|
||||
/// Define for FRC peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_FRC (&SL_BUS_CLOCK_FRC_VALUE)
|
||||
|
||||
/// Define for FSRCO peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_FSRCO (&SL_BUS_CLOCK_FSRCO_VALUE)
|
||||
|
||||
/// Define for GPCRC0 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_GPCRC0 (&SL_BUS_CLOCK_GPCRC0_VALUE)
|
||||
|
||||
/// Define for GPIO peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_GPIO (&SL_BUS_CLOCK_GPIO_VALUE)
|
||||
|
||||
/// Define for HFRCO0 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_HFRCO0 (&SL_BUS_CLOCK_HFRCO0_VALUE)
|
||||
|
||||
/// Define for HFRCOEM23 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_HFRCOEM23 (&SL_BUS_CLOCK_HFRCOEM23_VALUE)
|
||||
|
||||
/// Define for HFXO0 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_HFXO0 (&SL_BUS_CLOCK_HFXO0_VALUE)
|
||||
|
||||
/// Define for HOSTMAILBOX peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_HOSTMAILBOX (&SL_BUS_CLOCK_HOSTMAILBOX_VALUE)
|
||||
|
||||
/// Define for HOSTPORTAL peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_HOSTPORTAL (&SL_BUS_CLOCK_HOSTPORTAL_VALUE)
|
||||
|
||||
/// Define for I2C0 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_I2C0 (&SL_BUS_CLOCK_I2C0_VALUE)
|
||||
|
||||
/// Define for I2C1 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_I2C1 (&SL_BUS_CLOCK_I2C1_VALUE)
|
||||
|
||||
/// Define for I2C2 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_I2C2 (&SL_BUS_CLOCK_I2C2_VALUE)
|
||||
|
||||
/// Define for I2C3 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_I2C3 (&SL_BUS_CLOCK_I2C3_VALUE)
|
||||
|
||||
/// Define for IADC0 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_IADC0 (&SL_BUS_CLOCK_IADC0_VALUE)
|
||||
|
||||
/// Define for ICACHE0 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_ICACHE0 (&SL_BUS_CLOCK_ICACHE0_VALUE)
|
||||
|
||||
/// Define for IFADCDEBUG peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_IFADCDEBUG (&SL_BUS_CLOCK_IFADCDEBUG_VALUE)
|
||||
|
||||
/// Define for KEYSCAN peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_KEYSCAN (&SL_BUS_CLOCK_KEYSCAN_VALUE)
|
||||
|
||||
/// Define for KSU peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_KSU (&SL_BUS_CLOCK_KSU_VALUE)
|
||||
|
||||
/// Define for L2ICACHE0 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_L2ICACHE0 (&SL_BUS_CLOCK_L2ICACHE0_VALUE)
|
||||
|
||||
/// Define for LCD peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_LCD (&SL_BUS_CLOCK_LCD_VALUE)
|
||||
|
||||
/// Define for LDMA0 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_LDMA0 (&SL_BUS_CLOCK_LDMA0_VALUE)
|
||||
|
||||
/// Define for LDMAXBAR0 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_LDMAXBAR0 (&SL_BUS_CLOCK_LDMAXBAR0_VALUE)
|
||||
|
||||
/// Define for LEDDRV0 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_LEDDRV0 (&SL_BUS_CLOCK_LEDDRV0_VALUE)
|
||||
|
||||
/// Define for LESENSE peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_LESENSE (&SL_BUS_CLOCK_LESENSE_VALUE)
|
||||
|
||||
/// Define for LETIMER0 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_LETIMER0 (&SL_BUS_CLOCK_LETIMER0_VALUE)
|
||||
|
||||
/// Define for LFRCO peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_LFRCO (&SL_BUS_CLOCK_LFRCO_VALUE)
|
||||
|
||||
/// Define for LFXO peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_LFXO (&SL_BUS_CLOCK_LFXO_VALUE)
|
||||
|
||||
/// Define for LPWAES peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_LPWAES (&SL_BUS_CLOCK_LPWAES_VALUE)
|
||||
|
||||
/// Define for LPW0PORTAL peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_LPW0PORTAL (&SL_BUS_CLOCK_LPW0PORTAL_VALUE)
|
||||
|
||||
/// Define for MODEM peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_MODEM (&SL_BUS_CLOCK_MODEM_VALUE)
|
||||
|
||||
/// Define for MSC peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_MSC (&SL_BUS_CLOCK_MSC_VALUE)
|
||||
|
||||
/// Define for MVP peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_MVP (&SL_BUS_CLOCK_MVP_VALUE)
|
||||
|
||||
/// Define for PCNT0 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_PCNT0 (&SL_BUS_CLOCK_PCNT0_VALUE)
|
||||
|
||||
/// Define for PDM peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_PDM (&SL_BUS_CLOCK_PDM_VALUE)
|
||||
|
||||
/// Define for PIXELRZ0 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_PIXELRZ0 (&SL_BUS_CLOCK_PIXELRZ0_VALUE)
|
||||
|
||||
/// Define for PIXELRZ1 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_PIXELRZ1 (&SL_BUS_CLOCK_PIXELRZ1_VALUE)
|
||||
|
||||
/// Define for PRORTC peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_PRORTC (&SL_BUS_CLOCK_PRORTC_VALUE)
|
||||
|
||||
/// Define for PROTIMER peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_PROTIMER (&SL_BUS_CLOCK_PROTIMER_VALUE)
|
||||
|
||||
/// Define for PRS peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_PRS (&SL_BUS_CLOCK_PRS_VALUE)
|
||||
|
||||
/// Define for RAC peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_RAC (&SL_BUS_CLOCK_RAC_VALUE)
|
||||
|
||||
/// Define for RADIOAES peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_RADIOAES (&SL_BUS_CLOCK_RADIOAES_VALUE)
|
||||
|
||||
/// Define for RDMAILBOX0 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_RDMAILBOX0 (&SL_BUS_CLOCK_RDMAILBOX0_VALUE)
|
||||
|
||||
/// Define for RDMAILBOX1 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_RDMAILBOX1 (&SL_BUS_CLOCK_RDMAILBOX1_VALUE)
|
||||
|
||||
/// Define for RDSCRATCHPAD peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_RDSCRATCHPAD (&SL_BUS_CLOCK_RDSCRATCHPAD_VALUE)
|
||||
|
||||
/// Define for RFCRC peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_RFCRC (&SL_BUS_CLOCK_RFCRC_VALUE)
|
||||
|
||||
/// Define for RFECA0 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_RFECA0 (&SL_BUS_CLOCK_RFECA0_VALUE)
|
||||
|
||||
/// Define for RFECA1 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_RFECA1 (&SL_BUS_CLOCK_RFECA1_VALUE)
|
||||
|
||||
/// Define for RFFPLL0 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_RFFPLL0 (&SL_BUS_CLOCK_RFFPLL0_VALUE)
|
||||
|
||||
/// Define for RFMAILBOX peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_RFMAILBOX (&SL_BUS_CLOCK_RFMAILBOX_VALUE)
|
||||
|
||||
/// Define for RFSCRATCHPAD peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_RFSCRATCHPAD (&SL_BUS_CLOCK_RFSCRATCHPAD_VALUE)
|
||||
|
||||
/// Define for RFSENSE peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_RFSENSE (&SL_BUS_CLOCK_RFSENSE_VALUE)
|
||||
|
||||
/// Define for RPA peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_RPA (&SL_BUS_CLOCK_RPA_VALUE)
|
||||
|
||||
/// Define for RTCC peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_RTCC (&SL_BUS_CLOCK_RTCC_VALUE)
|
||||
|
||||
/// Define for SCRATCHPAD peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_SCRATCHPAD (&SL_BUS_CLOCK_SCRATCHPAD_VALUE)
|
||||
|
||||
/// Define for SEMAILBOX peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_SEMAILBOX (&SL_BUS_CLOCK_SEMAILBOX_VALUE)
|
||||
|
||||
/// Define for SEMAPHORE0 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_SEMAPHORE0 (&SL_BUS_CLOCK_SEMAPHORE0_VALUE)
|
||||
|
||||
/// Define for SEMAPHORE1 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_SEMAPHORE1 (&SL_BUS_CLOCK_SEMAPHORE1_VALUE)
|
||||
|
||||
/// Define for SEPORTAL peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_SEPORTAL (&SL_BUS_CLOCK_SEPORTAL_VALUE)
|
||||
|
||||
/// Define for SMU peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_SMU (&SL_BUS_CLOCK_SMU_VALUE)
|
||||
|
||||
/// Define for SOCPLL0 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_SOCPLL0 (&SL_BUS_CLOCK_SOCPLL0_VALUE)
|
||||
|
||||
/// Define for SYMCRYPTO peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_SYMCRYPTO (&SL_BUS_CLOCK_SYMCRYPTO_VALUE)
|
||||
|
||||
/// Define for SYNTH peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_SYNTH (&SL_BUS_CLOCK_SYNTH_VALUE)
|
||||
|
||||
/// Define for SYSCFG peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_SYSCFG (&SL_BUS_CLOCK_SYSCFG_VALUE)
|
||||
|
||||
/// Define for SYSRTC0 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_SYSRTC0 (&SL_BUS_CLOCK_SYSRTC0_VALUE)
|
||||
|
||||
/// Define for TIMER0 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_TIMER0 (&SL_BUS_CLOCK_TIMER0_VALUE)
|
||||
|
||||
/// Define for TIMER1 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_TIMER1 (&SL_BUS_CLOCK_TIMER1_VALUE)
|
||||
|
||||
/// Define for TIMER2 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_TIMER2 (&SL_BUS_CLOCK_TIMER2_VALUE)
|
||||
|
||||
/// Define for TIMER3 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_TIMER3 (&SL_BUS_CLOCK_TIMER3_VALUE)
|
||||
|
||||
/// Define for TIMER4 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_TIMER4 (&SL_BUS_CLOCK_TIMER4_VALUE)
|
||||
|
||||
/// Define for TIMER5 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_TIMER5 (&SL_BUS_CLOCK_TIMER5_VALUE)
|
||||
|
||||
/// Define for TIMER6 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_TIMER6 (&SL_BUS_CLOCK_TIMER6_VALUE)
|
||||
|
||||
/// Define for TIMER7 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_TIMER7 (&SL_BUS_CLOCK_TIMER7_VALUE)
|
||||
|
||||
/// Define for TIMER8 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_TIMER8 (&SL_BUS_CLOCK_TIMER8_VALUE)
|
||||
|
||||
/// Define for TIMER9 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_TIMER9 (&SL_BUS_CLOCK_TIMER9_VALUE)
|
||||
|
||||
/// Define for ULFRCO peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_ULFRCO (&SL_BUS_CLOCK_ULFRCO_VALUE)
|
||||
|
||||
/// Define for USART0 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_USART0 (&SL_BUS_CLOCK_USART0_VALUE)
|
||||
|
||||
/// Define for USART1 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_USART1 (&SL_BUS_CLOCK_USART1_VALUE)
|
||||
|
||||
/// Define for USART2 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_USART2 (&SL_BUS_CLOCK_USART2_VALUE)
|
||||
|
||||
/// Define for USB peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_USB (&SL_BUS_CLOCK_USB_VALUE)
|
||||
|
||||
/// Define for VDAC0 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_VDAC0 (&SL_BUS_CLOCK_VDAC0_VALUE)
|
||||
|
||||
/// Define for VDAC1 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_VDAC1 (&SL_BUS_CLOCK_VDAC1_VALUE)
|
||||
|
||||
/// Define for WDOG0 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_WDOG0 (&SL_BUS_CLOCK_WDOG0_VALUE)
|
||||
|
||||
/// Define for WDOG1 peripheral bus clock pointer.
|
||||
#define SL_BUS_CLOCK_WDOG1 (&SL_BUS_CLOCK_WDOG1_VALUE)
|
||||
|
||||
/// @} (end bus_clock_defines)
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// TYPEDEFS
|
||||
|
||||
/// The bus clock typedef.
|
||||
typedef const uint32_t* sl_bus_clock_t;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// EXTERNS
|
||||
|
||||
/// @cond DO_NOT_INCLUDE_WITH_DOXYGEN
|
||||
|
||||
// External declaration for invalid peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_INVALID_VALUE;
|
||||
|
||||
// External declaration for ACMP0 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_ACMP0_VALUE;
|
||||
|
||||
// External declaration for ACMP1 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_ACMP1_VALUE;
|
||||
|
||||
// External declaration for ADC0 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_ADC0_VALUE;
|
||||
|
||||
// External declaration for AGC peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_AGC_VALUE;
|
||||
|
||||
// External declaration for AMUXCP0 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_AMUXCP0_VALUE;
|
||||
|
||||
// External declaration for BUFC peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_BUFC_VALUE;
|
||||
|
||||
// External declaration for BURAM peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_BURAM_VALUE;
|
||||
|
||||
// External declaration for BURTC peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_BURTC_VALUE;
|
||||
|
||||
// External declaration for CRYPTOACC peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_CRYPTOACC_VALUE;
|
||||
|
||||
// External declaration for DCDC peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_DCDC_VALUE;
|
||||
|
||||
// External declaration for DEVINFO peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_DEVINFO_VALUE;
|
||||
|
||||
// External declaration for DMEM peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_DMEM_VALUE;
|
||||
|
||||
// External declaration for DPLL0 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_DPLL0_VALUE;
|
||||
|
||||
// External declaration for ECAIFADC peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_ECAIFADC_VALUE;
|
||||
|
||||
// External declaration for ETAMPDET peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_ETAMPDET_VALUE;
|
||||
|
||||
// External declaration for EUART0 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_EUART0_VALUE;
|
||||
|
||||
// External declaration for EUSART0 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_EUSART0_VALUE;
|
||||
|
||||
// External declaration for EUSART1 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_EUSART1_VALUE;
|
||||
|
||||
// External declaration for EUSART2 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_EUSART2_VALUE;
|
||||
|
||||
// External declaration for EUSART3 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_EUSART3_VALUE;
|
||||
|
||||
// External declaration for EUSART4 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_EUSART4_VALUE;
|
||||
|
||||
// External declaration for FRC peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_FRC_VALUE;
|
||||
|
||||
// External declaration for FSRCO peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_FSRCO_VALUE;
|
||||
|
||||
// External declaration for GPCRC0 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_GPCRC0_VALUE;
|
||||
|
||||
// External declaration for GPIO peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_GPIO_VALUE;
|
||||
|
||||
// External declaration for HFRCO0 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_HFRCO0_VALUE;
|
||||
|
||||
// External declaration for HFRCOEM23 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_HFRCOEM23_VALUE;
|
||||
|
||||
// External declaration for HFXO0 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_HFXO0_VALUE;
|
||||
|
||||
// External declaration for HOSTMAILBOX peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_HOSTMAILBOX_VALUE;
|
||||
|
||||
// External declaration for HOSTPORTAL peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_HOSTPORTAL_VALUE;
|
||||
|
||||
// External declaration for I2C0 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_I2C0_VALUE;
|
||||
|
||||
// External declaration for I2C1 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_I2C1_VALUE;
|
||||
|
||||
// External declaration for I2C2 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_I2C2_VALUE;
|
||||
|
||||
// External declaration for I2C3 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_I2C3_VALUE;
|
||||
|
||||
// External declaration for IADC0 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_IADC0_VALUE;
|
||||
|
||||
// External declaration for ICACHE0 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_ICACHE0_VALUE;
|
||||
|
||||
// External declaration for IFADCDEBUG peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_IFADCDEBUG_VALUE;
|
||||
|
||||
// External declaration for KEYSCAN peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_KEYSCAN_VALUE;
|
||||
|
||||
// External declaration for KSU peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_KSU_VALUE;
|
||||
|
||||
// External declaration for L2ICACHE0 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_L2ICACHE0_VALUE;
|
||||
|
||||
// External declaration for LCD peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_LCD_VALUE;
|
||||
|
||||
// External declaration for LDMA0 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_LDMA0_VALUE;
|
||||
|
||||
// External declaration for LDMAXBAR0 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_LDMAXBAR0_VALUE;
|
||||
|
||||
// External declaration for LEDDRV0 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_LEDDRV0_VALUE;
|
||||
|
||||
// External declaration for LESENSE peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_LESENSE_VALUE;
|
||||
|
||||
// External declaration for LETIMER0 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_LETIMER0_VALUE;
|
||||
|
||||
// External declaration for LFRCO peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_LFRCO_VALUE;
|
||||
|
||||
// External declaration for LFXO peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_LFXO_VALUE;
|
||||
|
||||
// External declaration for LPWAES peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_LPWAES_VALUE;
|
||||
|
||||
// External declaration for LPW0PORTAL peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_LPW0PORTAL_VALUE;
|
||||
|
||||
// External declaration for MODEM peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_MODEM_VALUE;
|
||||
|
||||
// External declaration for MSC peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_MSC_VALUE;
|
||||
|
||||
// External declaration for MVP peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_MVP_VALUE;
|
||||
|
||||
// External declaration for PCNT0 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_PCNT0_VALUE;
|
||||
|
||||
// External declaration for PDM peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_PDM_VALUE;
|
||||
|
||||
// External declaration for PIXELRZ0 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_PIXELRZ0_VALUE;
|
||||
|
||||
// External declaration for PIXELRZ1 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_PIXELRZ1_VALUE;
|
||||
|
||||
// External declaration for PRORTC peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_PRORTC_VALUE;
|
||||
|
||||
// External declaration for PROTIMER peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_PROTIMER_VALUE;
|
||||
|
||||
// External declaration for PRS peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_PRS_VALUE;
|
||||
|
||||
// External declaration for RAC peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_RAC_VALUE;
|
||||
|
||||
// External declaration for RADIOAES peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_RADIOAES_VALUE;
|
||||
|
||||
// External declaration for RDMAILBOX0 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_RDMAILBOX0_VALUE;
|
||||
|
||||
// External declaration for RDMAILBOX1 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_RDMAILBOX1_VALUE;
|
||||
|
||||
// External declaration for RDSCRATCHPAD peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_RDSCRATCHPAD_VALUE;
|
||||
|
||||
// External declaration for RFCRC peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_RFCRC_VALUE;
|
||||
|
||||
// External declaration for RFECA0 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_RFECA0_VALUE;
|
||||
|
||||
// External declaration for RFECA1 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_RFECA1_VALUE;
|
||||
|
||||
// External declaration for RFFPLL0 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_RFFPLL0_VALUE;
|
||||
|
||||
// External declaration for RFMAILBOX peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_RFMAILBOX_VALUE;
|
||||
|
||||
// External declaration for RFSCRATCHPAD peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_RFSCRATCHPAD_VALUE;
|
||||
|
||||
// External declaration for RFSENSE peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_RFSENSE_VALUE;
|
||||
|
||||
// External declaration for RPA peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_RPA_VALUE;
|
||||
|
||||
// External declaration for RTCC peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_RTCC_VALUE;
|
||||
|
||||
// External declaration for SCRATCHPAD peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_SCRATCHPAD_VALUE;
|
||||
|
||||
// External declaration for SEMAILBOX peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_SEMAILBOX_VALUE;
|
||||
|
||||
// External declaration for SEMAPHORE0 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_SEMAPHORE0_VALUE;
|
||||
|
||||
// External declaration for SEMAPHORE1 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_SEMAPHORE1_VALUE;
|
||||
|
||||
// External declaration for SEPORTAL peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_SEPORTAL_VALUE;
|
||||
|
||||
// External declaration for SMU peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_SMU_VALUE;
|
||||
|
||||
// External declaration for SOCPLL0 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_SOCPLL0_VALUE;
|
||||
|
||||
// External declaration for SYMCRYPTO peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_SYMCRYPTO_VALUE;
|
||||
|
||||
// External declaration for SYNTH peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_SYNTH_VALUE;
|
||||
|
||||
// External declaration for SYSCFG peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_SYSCFG_VALUE;
|
||||
|
||||
// External declaration for SYSRTC0 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_SYSRTC0_VALUE;
|
||||
|
||||
// External declaration for TIMER0 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_TIMER0_VALUE;
|
||||
|
||||
// External declaration for TIMER1 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_TIMER1_VALUE;
|
||||
|
||||
// External declaration for TIMER2 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_TIMER2_VALUE;
|
||||
|
||||
// External declaration for TIMER3 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_TIMER3_VALUE;
|
||||
|
||||
// External declaration for TIMER4 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_TIMER4_VALUE;
|
||||
|
||||
// External declaration for TIMER5 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_TIMER5_VALUE;
|
||||
|
||||
// External declaration for TIMER6 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_TIMER6_VALUE;
|
||||
|
||||
// External declaration for TIMER7 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_TIMER7_VALUE;
|
||||
|
||||
// External declaration for TIMER8 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_TIMER8_VALUE;
|
||||
|
||||
// External declaration for TIMER9 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_TIMER9_VALUE;
|
||||
|
||||
// External declaration for ULFRCO peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_ULFRCO_VALUE;
|
||||
|
||||
// External declaration for USART0 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_USART0_VALUE;
|
||||
|
||||
// External declaration for USART1 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_USART1_VALUE;
|
||||
|
||||
// External declaration for USART2 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_USART2_VALUE;
|
||||
|
||||
// External declaration for USB peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_USB_VALUE;
|
||||
|
||||
// External declaration for VDAC0 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_VDAC0_VALUE;
|
||||
|
||||
// External declaration for VDAC1 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_VDAC1_VALUE;
|
||||
|
||||
// External declaration for WDOG0 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_WDOG0_VALUE;
|
||||
|
||||
// External declaration for WDOG1 peripheral bus clock value.
|
||||
extern const uint32_t SL_BUS_CLOCK_WDOG1_VALUE;
|
||||
|
||||
/// @endcond
|
||||
|
||||
/** @} (end addtogroup device_clock) */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // SL_DEVICE_CLOCK_H
|
||||
670
Libs/platform/service/device_manager/inc/sl_device_gpio.h
Normal file
670
Libs/platform/service/device_manager/inc/sl_device_gpio.h
Normal file
@@ -0,0 +1,670 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief Device Manager GPIO.
|
||||
*******************************************************************************
|
||||
* # 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.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef SL_DEVICE_GPIO_H
|
||||
#define SL_DEVICE_GPIO_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "sl_enum.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/***************************************************************************//**
|
||||
* @addtogroup device_gpio Device Manager GPIO
|
||||
* @details
|
||||
* ## Overview
|
||||
*
|
||||
* The Device Manager GPIO component defines the macros,
|
||||
* structures, and enums that are used common across GPIO driver and
|
||||
* peripheral.
|
||||
*
|
||||
* @{
|
||||
******************************************************************************/
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// ENUMS
|
||||
|
||||
/// GPIO ports IDs.
|
||||
SL_ENUM(sl_gpio_port_t) {
|
||||
SL_GPIO_PORT_A = 0,
|
||||
SL_GPIO_PORT_B = 1,
|
||||
SL_GPIO_PORT_C = 2,
|
||||
SL_GPIO_PORT_D = 3,
|
||||
SL_GPIO_PORT_E = 4,
|
||||
SL_GPIO_PORT_F = 5,
|
||||
SL_GPIO_PORT_G = 6,
|
||||
SL_GPIO_PORT_H = 7,
|
||||
SL_GPIO_PORT_I = 8,
|
||||
SL_GPIO_PORT_J = 9,
|
||||
SL_GPIO_PORT_K = 10,
|
||||
};
|
||||
|
||||
/// GPIO Pin Modes.
|
||||
SL_ENUM(sl_gpio_mode_t) {
|
||||
/// Input disabled. Pull-up if DOUT is set.
|
||||
SL_GPIO_MODE_DISABLED,
|
||||
|
||||
/// Input enabled. Filter if DOUT is set.
|
||||
SL_GPIO_MODE_INPUT,
|
||||
|
||||
/// Input enabled. DOUT determines pull direction.
|
||||
SL_GPIO_MODE_INPUT_PULL,
|
||||
|
||||
/// Input enabled with filter. DOUT determines pull direction.
|
||||
SL_GPIO_MODE_INPUT_PULL_FILTER,
|
||||
|
||||
/// Push-pull output.
|
||||
SL_GPIO_MODE_PUSH_PULL,
|
||||
|
||||
/// Push-pull using alternate control.
|
||||
SL_GPIO_MODE_PUSH_PULL_ALTERNATE,
|
||||
|
||||
/// Wired-or output.
|
||||
SL_GPIO_MODE_WIRED_OR,
|
||||
|
||||
/// Wired-or output with pull-down.
|
||||
SL_GPIO_MODE_WIRED_OR_PULL_DOWN,
|
||||
|
||||
/// Open-drain output.
|
||||
SL_GPIO_MODE_WIRED_AND,
|
||||
|
||||
/// Open-drain output with filter.
|
||||
SL_GPIO_MODE_WIRED_AND_FILTER,
|
||||
|
||||
/// Open-drain output with pull-up.
|
||||
SL_GPIO_MODE_WIRED_AND_PULLUP,
|
||||
|
||||
/// Open-drain output with filter and pull-up.
|
||||
SL_GPIO_MODE_WIRED_AND_PULLUP_FILTER,
|
||||
|
||||
/// Open-drain output using alternate control.
|
||||
SL_GPIO_MODE_WIRED_AND_ALTERNATE,
|
||||
|
||||
/// Open-drain output using alternate control with filter.
|
||||
SL_GPIO_MODE_WIRED_AND_ALTERNATE_FILTER,
|
||||
|
||||
/// Open-drain output using alternate control with pull-up.
|
||||
SL_GPIO_MODE_WIRED_AND_ALTERNATE_PULLUP,
|
||||
|
||||
/// Open-drain output using alternate control with filter and pull-up.
|
||||
SL_GPIO_MODE_WIRED_AND_ALTERNATE_PULLUP_FILTER,
|
||||
};
|
||||
|
||||
/// GPIO Interrupt Configuration flags.
|
||||
SL_ENUM(sl_gpio_interrupt_flag_t) {
|
||||
/// No edge configured.
|
||||
SL_GPIO_INTERRUPT_NO_EDGE = 0,
|
||||
|
||||
/// Interrupt on rising edge.
|
||||
SL_GPIO_INTERRUPT_RISING_EDGE = (1 << 0),
|
||||
|
||||
/// Interrupt on falling edge.
|
||||
SL_GPIO_INTERRUPT_FALLING_EDGE = (1 << 1),
|
||||
|
||||
/// Interrupt on both rising and falling edge.
|
||||
SL_GPIO_INTERRUPT_RISING_FALLING_EDGE = (1 << 2)
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
******************************** DEFINES **********************************
|
||||
******************************************************************************/
|
||||
|
||||
#define SL_GPIO_INTERRUPT_UNAVAILABLE (-1)
|
||||
|
||||
/// Validation of flag.
|
||||
#define SL_GPIO_FLAG_IS_VALID(flag) ((flag == SL_GPIO_INTERRUPT_NO_EDGE) || (flag == SL_GPIO_INTERRUPT_RISING_EDGE) || (flag == SL_GPIO_INTERRUPT_FALLING_EDGE) || (flag == SL_GPIO_INTERRUPT_RISING_FALLING_EDGE))
|
||||
|
||||
/// Define for available ports and pins
|
||||
#define PA0 (&pa0)
|
||||
#define PA1 (&pa1)
|
||||
#define PA2 (&pa2)
|
||||
#define PA3 (&pa3)
|
||||
#define PA4 (&pa4)
|
||||
#define PA5 (&pa5)
|
||||
#define PA6 (&pa6)
|
||||
#define PA7 (&pa7)
|
||||
#define PA8 (&pa8)
|
||||
#define PA9 (&pa9)
|
||||
#define PA10 (&pa10)
|
||||
#define PA11 (&pa11)
|
||||
#define PA12 (&pa12)
|
||||
#define PA13 (&pa13)
|
||||
#define PA14 (&pa14)
|
||||
#define PA15 (&pa15)
|
||||
#define PA16 (&pa16)
|
||||
#define PA17 (&pa17)
|
||||
#define PA18 (&pa18)
|
||||
#define PA19 (&pa19)
|
||||
#define PA20 (&pa20)
|
||||
#define PA21 (&pa21)
|
||||
#define PA22 (&pa22)
|
||||
#define PA23 (&pa23)
|
||||
#define PA24 (&pa24)
|
||||
#define PA25 (&pa25)
|
||||
#define PA26 (&pa26)
|
||||
#define PA27 (&pa27)
|
||||
#define PA28 (&pa28)
|
||||
#define PA29 (&pa29)
|
||||
#define PA30 (&pa30)
|
||||
#define PA31 (&pa31)
|
||||
|
||||
#define PB0 (&pb0)
|
||||
#define PB1 (&pb1)
|
||||
#define PB2 (&pb2)
|
||||
#define PB3 (&pb3)
|
||||
#define PB4 (&pb4)
|
||||
#define PB5 (&pb5)
|
||||
#define PB6 (&pb6)
|
||||
#define PB7 (&pb7)
|
||||
#define PB8 (&pb8)
|
||||
#define PB9 (&pb9)
|
||||
#define PB10 (&pb10)
|
||||
#define PB11 (&pb11)
|
||||
#define PB12 (&pb12)
|
||||
#define PB13 (&pb13)
|
||||
#define PB14 (&pb14)
|
||||
#define PB15 (&pb15)
|
||||
#define PB16 (&pb16)
|
||||
#define PB17 (&pb17)
|
||||
#define PB18 (&pb18)
|
||||
#define PB19 (&pb19)
|
||||
#define PB20 (&pb20)
|
||||
#define PB21 (&pb21)
|
||||
#define PB22 (&pb22)
|
||||
#define PB23 (&pb23)
|
||||
#define PB24 (&pb24)
|
||||
#define PB25 (&pb25)
|
||||
#define PB26 (&pb26)
|
||||
#define PB27 (&pb27)
|
||||
#define PB28 (&pb28)
|
||||
#define PB29 (&pb29)
|
||||
#define PB30 (&pb30)
|
||||
#define PB31 (&pb31)
|
||||
|
||||
#define PC0 (&pc0)
|
||||
#define PC1 (&pc1)
|
||||
#define PC2 (&pc2)
|
||||
#define PC3 (&pc3)
|
||||
#define PC4 (&pc4)
|
||||
#define PC5 (&pc5)
|
||||
#define PC6 (&pc6)
|
||||
#define PC7 (&pc7)
|
||||
#define PC8 (&pc8)
|
||||
#define PC9 (&pc9)
|
||||
#define PC10 (&pc10)
|
||||
#define PC11 (&pc11)
|
||||
#define PC12 (&pc12)
|
||||
#define PC13 (&pc13)
|
||||
#define PC14 (&pc14)
|
||||
#define PC15 (&pc15)
|
||||
#define PC16 (&pc16)
|
||||
#define PC17 (&pc17)
|
||||
#define PC18 (&pc18)
|
||||
#define PC19 (&pc19)
|
||||
#define PC20 (&pc20)
|
||||
#define PC21 (&pc21)
|
||||
#define PC22 (&pc22)
|
||||
#define PC23 (&pc23)
|
||||
#define PC24 (&pc24)
|
||||
#define PC25 (&pc25)
|
||||
#define PC26 (&pc26)
|
||||
#define PC27 (&pc27)
|
||||
#define PC28 (&pc28)
|
||||
#define PC29 (&pc29)
|
||||
#define PC30 (&pc30)
|
||||
#define PC31 (&pc31)
|
||||
|
||||
#define PD0 (&pd0)
|
||||
#define PD1 (&pd1)
|
||||
#define PD2 (&pd2)
|
||||
#define PD3 (&pd3)
|
||||
#define PD4 (&pd4)
|
||||
#define PD5 (&pd5)
|
||||
#define PD6 (&pd6)
|
||||
#define PD7 (&pd7)
|
||||
#define PD8 (&pd8)
|
||||
#define PD9 (&pd9)
|
||||
#define PD10 (&pd10)
|
||||
#define PD11 (&pd11)
|
||||
#define PD12 (&pd12)
|
||||
#define PD13 (&pd13)
|
||||
#define PD14 (&pd14)
|
||||
#define PD15 (&pd15)
|
||||
#define PD16 (&pd16)
|
||||
#define PD17 (&pd17)
|
||||
#define PD18 (&pd18)
|
||||
#define PD19 (&pd19)
|
||||
#define PD20 (&pd20)
|
||||
#define PD21 (&pd21)
|
||||
#define PD22 (&pd22)
|
||||
#define PD23 (&pd23)
|
||||
#define PD24 (&pd24)
|
||||
#define PD25 (&pd25)
|
||||
#define PD26 (&pd26)
|
||||
#define PD27 (&pd27)
|
||||
#define PD28 (&pd28)
|
||||
#define PD29 (&pd29)
|
||||
#define PD30 (&pd30)
|
||||
#define PD31 (&pd31)
|
||||
|
||||
#define PE0 (&pe0)
|
||||
#define PE1 (&pe1)
|
||||
#define PE2 (&pe2)
|
||||
#define PE3 (&pe3)
|
||||
#define PE4 (&pe4)
|
||||
#define PE5 (&pe5)
|
||||
#define PE6 (&pe6)
|
||||
#define PE7 (&pe7)
|
||||
#define PE8 (&pe8)
|
||||
#define PE9 (&pe9)
|
||||
#define PE10 (&pe10)
|
||||
#define PE11 (&pe11)
|
||||
#define PE12 (&pe12)
|
||||
#define PE13 (&pe13)
|
||||
#define PE14 (&pe14)
|
||||
#define PE15 (&pe15)
|
||||
#define PE16 (&pe16)
|
||||
#define PE17 (&pe17)
|
||||
#define PE18 (&pe18)
|
||||
#define PE19 (&pe19)
|
||||
#define PE20 (&pe20)
|
||||
#define PE21 (&pe21)
|
||||
#define PE22 (&pe22)
|
||||
#define PE23 (&pe23)
|
||||
#define PE24 (&pe24)
|
||||
#define PE25 (&pe25)
|
||||
#define PE26 (&pe26)
|
||||
#define PE27 (&pe27)
|
||||
#define PE28 (&pe28)
|
||||
#define PE29 (&pe29)
|
||||
#define PE30 (&pe30)
|
||||
#define PE31 (&pe31)
|
||||
|
||||
#define PF0 (&pf0)
|
||||
#define PF1 (&pf1)
|
||||
#define PF2 (&pf2)
|
||||
#define PF3 (&pf3)
|
||||
#define PF4 (&pf4)
|
||||
#define PF5 (&pf5)
|
||||
#define PF6 (&pf6)
|
||||
#define PF7 (&pf7)
|
||||
#define PF8 (&pf8)
|
||||
#define PF9 (&pf9)
|
||||
#define PF10 (&pf10)
|
||||
#define PF11 (&pf11)
|
||||
#define PF12 (&pf12)
|
||||
#define PF13 (&pf13)
|
||||
#define PF14 (&pf14)
|
||||
#define PF15 (&pf15)
|
||||
#define PF16 (&pf16)
|
||||
#define PF17 (&pf17)
|
||||
#define PF18 (&pf18)
|
||||
#define PF19 (&pf19)
|
||||
#define PF20 (&pf20)
|
||||
#define PF21 (&pf21)
|
||||
#define PF22 (&pf22)
|
||||
#define PF23 (&pf23)
|
||||
#define PF24 (&pf24)
|
||||
#define PF25 (&pf25)
|
||||
#define PF26 (&pf26)
|
||||
#define PF27 (&pf27)
|
||||
#define PF28 (&pf28)
|
||||
#define PF29 (&pf29)
|
||||
#define PF30 (&pf30)
|
||||
#define PF31 (&pf31)
|
||||
|
||||
#define PG0 (&pg0)
|
||||
#define PG1 (&pg1)
|
||||
#define PG2 (&pg2)
|
||||
#define PG3 (&pg3)
|
||||
#define PG4 (&pg4)
|
||||
#define PG5 (&pg5)
|
||||
#define PG6 (&pg6)
|
||||
#define PG7 (&pg7)
|
||||
#define PG8 (&pg8)
|
||||
#define PG9 (&pg9)
|
||||
#define PG10 (&pg10)
|
||||
#define PG11 (&pg11)
|
||||
#define PG12 (&pg12)
|
||||
#define PG13 (&pg13)
|
||||
#define PG14 (&pg14)
|
||||
#define PG15 (&pg15)
|
||||
#define PG16 (&pg16)
|
||||
#define PG17 (&pg17)
|
||||
#define PG18 (&pg18)
|
||||
#define PG19 (&pg19)
|
||||
#define PG20 (&pg20)
|
||||
#define PG21 (&pg21)
|
||||
#define PG22 (&pg22)
|
||||
#define PG23 (&pg23)
|
||||
#define PG24 (&pg24)
|
||||
#define PG25 (&pg25)
|
||||
#define PG26 (&pg26)
|
||||
#define PG27 (&pg27)
|
||||
#define PG28 (&pg28)
|
||||
#define PG29 (&pg29)
|
||||
#define PG30 (&pg30)
|
||||
#define PG31 (&pg31)
|
||||
|
||||
#define PH0 (&ph0)
|
||||
#define PH1 (&ph1)
|
||||
#define PH2 (&ph2)
|
||||
#define PH3 (&ph3)
|
||||
#define PH4 (&ph4)
|
||||
#define PH5 (&ph5)
|
||||
#define PH6 (&ph6)
|
||||
#define PH7 (&ph7)
|
||||
#define PH8 (&ph8)
|
||||
#define PH9 (&ph9)
|
||||
#define PH10 (&ph10)
|
||||
#define PH11 (&ph11)
|
||||
#define PH12 (&ph12)
|
||||
#define PH13 (&ph13)
|
||||
#define PH14 (&ph14)
|
||||
#define PH15 (&ph15)
|
||||
#define PH16 (&ph16)
|
||||
#define PH17 (&ph17)
|
||||
#define PH18 (&ph18)
|
||||
#define PH19 (&ph19)
|
||||
#define PH20 (&ph20)
|
||||
#define PH21 (&ph21)
|
||||
#define PH22 (&ph22)
|
||||
#define PH23 (&ph23)
|
||||
#define PH24 (&ph24)
|
||||
#define PH25 (&ph25)
|
||||
#define PH26 (&ph26)
|
||||
#define PH27 (&ph27)
|
||||
#define PH28 (&ph28)
|
||||
#define PH29 (&ph29)
|
||||
#define PH30 (&ph30)
|
||||
#define PH31 (&ph31)
|
||||
|
||||
#define PI0 (&pi0)
|
||||
#define PI1 (&pi1)
|
||||
#define PI2 (&pi2)
|
||||
#define PI3 (&pi3)
|
||||
#define PI4 (&pi4)
|
||||
#define PI5 (&pi5)
|
||||
#define PI6 (&pi6)
|
||||
#define PI7 (&pi7)
|
||||
#define PI8 (&pi8)
|
||||
#define PI9 (&pi9)
|
||||
#define PI10 (&pi10)
|
||||
#define PI11 (&pi11)
|
||||
#define PI12 (&pi12)
|
||||
#define PI13 (&pi13)
|
||||
#define PI14 (&pi14)
|
||||
#define PI15 (&pi15)
|
||||
#define PI16 (&pi16)
|
||||
#define PI17 (&pi17)
|
||||
#define PI18 (&pi18)
|
||||
#define PI19 (&pi19)
|
||||
#define PI20 (&pi20)
|
||||
#define PI21 (&pi21)
|
||||
#define PI22 (&pi22)
|
||||
#define PI23 (&pi23)
|
||||
#define PI24 (&pi24)
|
||||
#define PI25 (&pi25)
|
||||
#define PI26 (&pi26)
|
||||
#define PI27 (&pi27)
|
||||
#define PI28 (&pi28)
|
||||
#define PI29 (&pi29)
|
||||
#define PI30 (&pi30)
|
||||
#define PI31 (&pi31)
|
||||
|
||||
#define PJ0 (&pj0)
|
||||
#define PJ1 (&pj1)
|
||||
#define PJ2 (&pj2)
|
||||
#define PJ3 (&pj3)
|
||||
#define PJ4 (&pj4)
|
||||
#define PJ5 (&pj5)
|
||||
#define PJ6 (&pj6)
|
||||
#define PJ7 (&pj7)
|
||||
#define PJ8 (&pj8)
|
||||
#define PJ9 (&pj9)
|
||||
#define PJ10 (&pj10)
|
||||
#define PJ11 (&pj11)
|
||||
#define PJ12 (&pj12)
|
||||
#define PJ13 (&pj13)
|
||||
#define PJ14 (&pj14)
|
||||
#define PJ15 (&pj15)
|
||||
#define PJ16 (&pj16)
|
||||
#define PJ17 (&pj17)
|
||||
#define PJ18 (&pj18)
|
||||
#define PJ19 (&pj19)
|
||||
#define PJ20 (&pj20)
|
||||
#define PJ21 (&pj21)
|
||||
#define PJ22 (&pj22)
|
||||
#define PJ23 (&pj23)
|
||||
#define PJ24 (&pj24)
|
||||
#define PJ25 (&pj25)
|
||||
#define PJ26 (&pj26)
|
||||
#define PJ27 (&pj27)
|
||||
#define PJ28 (&pj28)
|
||||
#define PJ29 (&pj29)
|
||||
#define PJ30 (&pj30)
|
||||
#define PJ31 (&pj31)
|
||||
|
||||
#define PK0 (&pk0)
|
||||
#define PK1 (&pk1)
|
||||
#define PK2 (&pk2)
|
||||
#define PK3 (&pk3)
|
||||
#define PK4 (&pk4)
|
||||
#define PK5 (&pk5)
|
||||
#define PK6 (&pk6)
|
||||
#define PK7 (&pk7)
|
||||
#define PK8 (&pk8)
|
||||
#define PK9 (&pk9)
|
||||
#define PK10 (&pk10)
|
||||
#define PK11 (&pk11)
|
||||
#define PK12 (&pk12)
|
||||
#define PK13 (&pk13)
|
||||
#define PK14 (&pk14)
|
||||
#define PK15 (&pk15)
|
||||
#define PK16 (&pk16)
|
||||
#define PK17 (&pk17)
|
||||
#define PK18 (&pk18)
|
||||
#define PK19 (&pk19)
|
||||
#define PK20 (&pk20)
|
||||
#define PK21 (&pk21)
|
||||
#define PK22 (&pk22)
|
||||
#define PK23 (&pk23)
|
||||
#define PK24 (&pk24)
|
||||
#define PK25 (&pk25)
|
||||
#define PK26 (&pk26)
|
||||
#define PK27 (&pk27)
|
||||
#define PK28 (&pk28)
|
||||
#define PK29 (&pk29)
|
||||
#define PK30 (&pk30)
|
||||
#define PK31 (&pk31)
|
||||
|
||||
/*******************************************************************************
|
||||
******************************* STRUCTS ***********************************
|
||||
******************************************************************************/
|
||||
|
||||
/// Structure for GPIO Port and Pin.
|
||||
typedef struct {
|
||||
uint8_t port;
|
||||
uint8_t pin;
|
||||
} sl_gpio_t;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// EXTERNS
|
||||
|
||||
/// @cond DO_NOT_INCLUDE_WITH_DOXYGEN
|
||||
|
||||
extern const sl_gpio_t pa0;
|
||||
extern const sl_gpio_t pa1;
|
||||
extern const sl_gpio_t pa2;
|
||||
extern const sl_gpio_t pa3;
|
||||
extern const sl_gpio_t pa4;
|
||||
extern const sl_gpio_t pa5;
|
||||
extern const sl_gpio_t pa6;
|
||||
extern const sl_gpio_t pa7;
|
||||
extern const sl_gpio_t pa8;
|
||||
extern const sl_gpio_t pa9;
|
||||
extern const sl_gpio_t pa10;
|
||||
extern const sl_gpio_t pa11;
|
||||
extern const sl_gpio_t pa12;
|
||||
extern const sl_gpio_t pa13;
|
||||
extern const sl_gpio_t pa14;
|
||||
extern const sl_gpio_t pa15;
|
||||
extern const sl_gpio_t pa16;
|
||||
extern const sl_gpio_t pa17;
|
||||
extern const sl_gpio_t pa18;
|
||||
extern const sl_gpio_t pa19;
|
||||
extern const sl_gpio_t pa20;
|
||||
extern const sl_gpio_t pa21;
|
||||
extern const sl_gpio_t pa22;
|
||||
extern const sl_gpio_t pa23;
|
||||
extern const sl_gpio_t pa24;
|
||||
extern const sl_gpio_t pa25;
|
||||
extern const sl_gpio_t pa26;
|
||||
extern const sl_gpio_t pa27;
|
||||
extern const sl_gpio_t pa28;
|
||||
extern const sl_gpio_t pa29;
|
||||
extern const sl_gpio_t pa30;
|
||||
extern const sl_gpio_t pa31;
|
||||
extern const sl_gpio_t pa32;
|
||||
|
||||
extern const sl_gpio_t pb0;
|
||||
extern const sl_gpio_t pb1;
|
||||
extern const sl_gpio_t pb2;
|
||||
extern const sl_gpio_t pb3;
|
||||
extern const sl_gpio_t pb4;
|
||||
extern const sl_gpio_t pb5;
|
||||
extern const sl_gpio_t pb6;
|
||||
extern const sl_gpio_t pb7;
|
||||
extern const sl_gpio_t pb8;
|
||||
extern const sl_gpio_t pb9;
|
||||
extern const sl_gpio_t pb10;
|
||||
extern const sl_gpio_t pb11;
|
||||
extern const sl_gpio_t pb12;
|
||||
extern const sl_gpio_t pb13;
|
||||
extern const sl_gpio_t pb14;
|
||||
extern const sl_gpio_t pb15;
|
||||
extern const sl_gpio_t pb16;
|
||||
extern const sl_gpio_t pb17;
|
||||
extern const sl_gpio_t pb18;
|
||||
extern const sl_gpio_t pb19;
|
||||
extern const sl_gpio_t pb20;
|
||||
extern const sl_gpio_t pb21;
|
||||
extern const sl_gpio_t pb22;
|
||||
extern const sl_gpio_t pb23;
|
||||
extern const sl_gpio_t pb24;
|
||||
extern const sl_gpio_t pb25;
|
||||
extern const sl_gpio_t pb26;
|
||||
extern const sl_gpio_t pb27;
|
||||
extern const sl_gpio_t pb28;
|
||||
extern const sl_gpio_t pb29;
|
||||
extern const sl_gpio_t pb30;
|
||||
extern const sl_gpio_t pb31;
|
||||
extern const sl_gpio_t pb32;
|
||||
|
||||
extern const sl_gpio_t pc0;
|
||||
extern const sl_gpio_t pc1;
|
||||
extern const sl_gpio_t pc2;
|
||||
extern const sl_gpio_t pc3;
|
||||
extern const sl_gpio_t pc4;
|
||||
extern const sl_gpio_t pc5;
|
||||
extern const sl_gpio_t pc6;
|
||||
extern const sl_gpio_t pc7;
|
||||
extern const sl_gpio_t pc8;
|
||||
extern const sl_gpio_t pc9;
|
||||
extern const sl_gpio_t pc10;
|
||||
extern const sl_gpio_t pc11;
|
||||
extern const sl_gpio_t pc12;
|
||||
extern const sl_gpio_t pc13;
|
||||
extern const sl_gpio_t pc14;
|
||||
extern const sl_gpio_t pc15;
|
||||
extern const sl_gpio_t pc16;
|
||||
extern const sl_gpio_t pc17;
|
||||
extern const sl_gpio_t pc18;
|
||||
extern const sl_gpio_t pc19;
|
||||
extern const sl_gpio_t pc20;
|
||||
extern const sl_gpio_t pc21;
|
||||
extern const sl_gpio_t pc22;
|
||||
extern const sl_gpio_t pc23;
|
||||
extern const sl_gpio_t pc24;
|
||||
extern const sl_gpio_t pc25;
|
||||
extern const sl_gpio_t pc26;
|
||||
extern const sl_gpio_t pc27;
|
||||
extern const sl_gpio_t pc28;
|
||||
extern const sl_gpio_t pc29;
|
||||
extern const sl_gpio_t pc30;
|
||||
extern const sl_gpio_t pc31;
|
||||
extern const sl_gpio_t pc32;
|
||||
|
||||
extern const sl_gpio_t pd0;
|
||||
extern const sl_gpio_t pd1;
|
||||
extern const sl_gpio_t pd2;
|
||||
extern const sl_gpio_t pd3;
|
||||
extern const sl_gpio_t pd4;
|
||||
extern const sl_gpio_t pd5;
|
||||
extern const sl_gpio_t pd6;
|
||||
extern const sl_gpio_t pd7;
|
||||
extern const sl_gpio_t pd8;
|
||||
extern const sl_gpio_t pd9;
|
||||
extern const sl_gpio_t pd10;
|
||||
extern const sl_gpio_t pd11;
|
||||
extern const sl_gpio_t pd12;
|
||||
extern const sl_gpio_t pd13;
|
||||
extern const sl_gpio_t pd14;
|
||||
extern const sl_gpio_t pd15;
|
||||
extern const sl_gpio_t pd16;
|
||||
extern const sl_gpio_t pd17;
|
||||
extern const sl_gpio_t pd18;
|
||||
extern const sl_gpio_t pd19;
|
||||
extern const sl_gpio_t pd20;
|
||||
extern const sl_gpio_t pd21;
|
||||
extern const sl_gpio_t pd22;
|
||||
extern const sl_gpio_t pd23;
|
||||
extern const sl_gpio_t pd24;
|
||||
extern const sl_gpio_t pd25;
|
||||
extern const sl_gpio_t pd26;
|
||||
extern const sl_gpio_t pd27;
|
||||
extern const sl_gpio_t pd28;
|
||||
extern const sl_gpio_t pd29;
|
||||
extern const sl_gpio_t pd30;
|
||||
extern const sl_gpio_t pd31;
|
||||
extern const sl_gpio_t pd32;
|
||||
|
||||
/// @endcond
|
||||
|
||||
/** @} (end addtogroup device_gpio) */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // SL_DEVICE_GPIO_H
|
||||
2821
Libs/platform/service/device_manager/inc/sl_device_peripheral.h
Normal file
2821
Libs/platform/service/device_manager/inc/sl_device_peripheral.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,65 @@
|
||||
/**************************************************************************//**
|
||||
* @file
|
||||
* @brief Device Manager API Definition
|
||||
******************************************************************************
|
||||
* # 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.
|
||||
*
|
||||
*****************************************************************************/
|
||||
#ifndef SL_DEVICE_PERIPHERAL_TYPES_H
|
||||
#define SL_DEVICE_PERIPHERAL_TYPES_H
|
||||
|
||||
#include "sl_device_clock.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/***************************************************************************//**
|
||||
* @addtogroup device_peripheral Device Abstraction Peripheral
|
||||
*
|
||||
* @{
|
||||
******************************************************************************/
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// TYPEDEFS
|
||||
|
||||
/// Define peripheral structure.
|
||||
typedef struct sl_peripheral {
|
||||
uint32_t base; ///< Peripheral base address.
|
||||
sl_clock_branch_t clk_branch; ///< Peripheral clock branch.
|
||||
sl_bus_clock_t bus_clock; ///< Peripheral bus clock.
|
||||
} sl_peripheral_val_t;
|
||||
|
||||
/// Define peripheral typedef.
|
||||
typedef const sl_peripheral_val_t* sl_peripheral_t;
|
||||
|
||||
/** @} (end addtogroup device_peripheral) */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // SL_DEVICE_PERIPHERAL_TYPES_H
|
||||
351
Libs/platform/service/device_manager/src/sl_device_clock.c
Normal file
351
Libs/platform/service/device_manager/src/sl_device_clock.c
Normal file
@@ -0,0 +1,351 @@
|
||||
/**************************************************************************//**
|
||||
* @file
|
||||
* @brief Device Manager Clock API Definition
|
||||
******************************************************************************
|
||||
* # 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_device_clock.h"
|
||||
#include "cmsis_compiler.h"
|
||||
|
||||
/***************************************************************************//**
|
||||
* @addtogroup device_clock Device Manager Clock
|
||||
* @{
|
||||
******************************************************************************/
|
||||
|
||||
// External declaration for ACMP0 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_ACMP0_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for ACMP1 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_ACMP1_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for ADC0 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_ADC0_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for AGC peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_AGC_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for AMUXCP0 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_AMUXCP0_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for BUFC peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_BUFC_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for BURAM peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_BURAM_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for BURTC peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_BURTC_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for CRYPTOACC peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_CRYPTOACC_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for DCDC peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_DCDC_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for DEVINFO peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_DEVINFO_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for DMEM peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_DMEM_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for DPLL0 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_DPLL0_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for ECAIFADC peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_ECAIFADC_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for ETAMPDET peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_ETAMPDET_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for EUART0 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_EUART0_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for EUSART0 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_EUSART0_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for EUSART1 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_EUSART1_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for EUSART2 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_EUSART2_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for EUSART3 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_EUSART3_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for EUSART4 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_EUSART4_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for FRC peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_FRC_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for FSRCO peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_FSRCO_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for GPCRC0 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_GPCRC0_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for GPIO peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_GPIO_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for HFRCO0 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_HFRCO0_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for HFRCOEM23 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_HFRCOEM23_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for HFXO0 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_HFXO0_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for HOSTMAILBOX peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_HOSTMAILBOX_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for HOSTPORTAL peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_HOSTPORTAL_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for I2C0 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_I2C0_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for I2C1 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_I2C1_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for I2C2 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_I2C2_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for I2C3 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_I2C3_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for IADC0 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_IADC0_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for ICACHE0 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_ICACHE0_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for IFADCDEBUG peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_IFADCDEBUG_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for KEYSCAN peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_KEYSCAN_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for KSU peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_KSU_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for L2ICACHE0 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_L2ICACHE0_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for LCD peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_LCD_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for LDMA0 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_LDMA0_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for LDMAXBAR0 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_LDMAXBAR0_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for LEDDRV0 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_LEDDRV0_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for LESENSE peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_LESENSE_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for LETIMER0 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_LETIMER0_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for LFRCO peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_LFRCO_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for LFXO peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_LFXO_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for LPWAES peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_LPWAES_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for LPW0PORTAL peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_LPW0PORTAL_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for MODEM peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_MODEM_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for MSC peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_MSC_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for MVP peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_MVP_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for PCNT0 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_PCNT0_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for PDM peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_PDM_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for PIXELRZ0 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_PIXELRZ0_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for PIXELRZ1 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_PIXELRZ1_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for PRORTC peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_PRORTC_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for PROTIMER peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_PROTIMER_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for PRS peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_PRS_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for RAC peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_RAC_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for RADIOAES peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_RADIOAES_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for RDMAILBOX0 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_RDMAILBOX0_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for RDMAILBOX1 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_RDMAILBOX1_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for RDSCRATCHPAD peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_RDSCRATCHPAD_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for RFCRC peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_RFCRC_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for RFECA0 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_RFECA0_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for RFECA1 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_RFECA1_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for RFFPLL0 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_RFFPLL0_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for RFMAILBOX peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_RFMAILBOX_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for RFSCRATCHPAD peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_RFSCRATCHPAD_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for RFSENSE peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_RFSENSE_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for RPA peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_RPA_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for RTCC peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_RTCC_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for SCRATCHPAD peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_SCRATCHPAD_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for SEMAILBOX peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_SEMAILBOX_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for SEMAPHORE0 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_SEMAPHORE0_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for SEMAPHORE1 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_SEMAPHORE1_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for SEPORTAL peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_SEPORTAL_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for SMU peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_SMU_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for SOCPLL0 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_SOCPLL0_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for SYMCRYPTO peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_SYMCRYPTO_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for SYNTH peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_SYNTH_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for SYSCFG peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_SYSCFG_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for SYSRTC0 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_SYSRTC0_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for TIMER0 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_TIMER0_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for TIMER1 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_TIMER1_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for TIMER2 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_TIMER2_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for TIMER3 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_TIMER3_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for TIMER4 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_TIMER4_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for TIMER5 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_TIMER5_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for TIMER6 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_TIMER6_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for TIMER7 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_TIMER7_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for TIMER8 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_TIMER8_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for TIMER9 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_TIMER9_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for ULFRCO peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_ULFRCO_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for USART0 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_USART0_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for USART1 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_USART1_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for USART2 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_USART2_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for USB peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_USB_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for VDAC0 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_VDAC0_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for VDAC1 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_VDAC1_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for WDOG0 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_WDOG0_VALUE = 0xFFFFFFFF;
|
||||
|
||||
// External declaration for WDOG1 peripheral bus clock value.
|
||||
__WEAK const uint32_t SL_BUS_CLOCK_WDOG1_VALUE = 0xFFFFFFFF;
|
||||
|
||||
/** @} (end addtogroup device_clock) */
|
||||
403
Libs/platform/service/device_manager/src/sl_device_gpio.c
Normal file
403
Libs/platform/service/device_manager/src/sl_device_gpio.c
Normal file
@@ -0,0 +1,403 @@
|
||||
/**************************************************************************//**
|
||||
* @file
|
||||
* @brief Device Manager Clock API Definition
|
||||
******************************************************************************
|
||||
* # 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_device_gpio.h"
|
||||
#include "cmsis_compiler.h"
|
||||
|
||||
/***************************************************************************//**
|
||||
* @addtogroup device_gpio Device Manager GPIO
|
||||
* @{
|
||||
******************************************************************************/
|
||||
|
||||
/// Declarations for port and pins
|
||||
const sl_gpio_t pa0 = { .port = SL_GPIO_PORT_A, .pin = 0 };
|
||||
const sl_gpio_t pa1 = { .port = SL_GPIO_PORT_A, .pin = 1 };
|
||||
const sl_gpio_t pa2 = { .port = SL_GPIO_PORT_A, .pin = 2 };
|
||||
const sl_gpio_t pa3 = { .port = SL_GPIO_PORT_A, .pin = 3 };
|
||||
const sl_gpio_t pa4 = { .port = SL_GPIO_PORT_A, .pin = 4 };
|
||||
const sl_gpio_t pa5 = { .port = SL_GPIO_PORT_A, .pin = 5 };
|
||||
const sl_gpio_t pa6 = { .port = SL_GPIO_PORT_A, .pin = 6 };
|
||||
const sl_gpio_t pa7 = { .port = SL_GPIO_PORT_A, .pin = 7 };
|
||||
const sl_gpio_t pa8 = { .port = SL_GPIO_PORT_A, .pin = 8 };
|
||||
const sl_gpio_t pa9 = { .port = SL_GPIO_PORT_A, .pin = 9 };
|
||||
const sl_gpio_t pa10 = { .port = SL_GPIO_PORT_A, .pin = 10 };
|
||||
const sl_gpio_t pa11 = { .port = SL_GPIO_PORT_A, .pin = 11 };
|
||||
const sl_gpio_t pa12 = { .port = SL_GPIO_PORT_A, .pin = 12 };
|
||||
const sl_gpio_t pa13 = { .port = SL_GPIO_PORT_A, .pin = 13 };
|
||||
const sl_gpio_t pa14 = { .port = SL_GPIO_PORT_A, .pin = 14 };
|
||||
const sl_gpio_t pa15 = { .port = SL_GPIO_PORT_A, .pin = 15 };
|
||||
const sl_gpio_t pa16 = { .port = SL_GPIO_PORT_A, .pin = 16 };
|
||||
const sl_gpio_t pa17 = { .port = SL_GPIO_PORT_A, .pin = 17 };
|
||||
const sl_gpio_t pa18 = { .port = SL_GPIO_PORT_A, .pin = 18 };
|
||||
const sl_gpio_t pa19 = { .port = SL_GPIO_PORT_A, .pin = 19 };
|
||||
const sl_gpio_t pa20 = { .port = SL_GPIO_PORT_A, .pin = 20 };
|
||||
const sl_gpio_t pa21 = { .port = SL_GPIO_PORT_A, .pin = 21 };
|
||||
const sl_gpio_t pa22 = { .port = SL_GPIO_PORT_A, .pin = 22 };
|
||||
const sl_gpio_t pa23 = { .port = SL_GPIO_PORT_A, .pin = 23 };
|
||||
const sl_gpio_t pa24 = { .port = SL_GPIO_PORT_A, .pin = 24 };
|
||||
const sl_gpio_t pa25 = { .port = SL_GPIO_PORT_A, .pin = 25 };
|
||||
const sl_gpio_t pa26 = { .port = SL_GPIO_PORT_A, .pin = 26 };
|
||||
const sl_gpio_t pa27 = { .port = SL_GPIO_PORT_A, .pin = 27 };
|
||||
const sl_gpio_t pa28 = { .port = SL_GPIO_PORT_A, .pin = 28 };
|
||||
const sl_gpio_t pa29 = { .port = SL_GPIO_PORT_A, .pin = 29 };
|
||||
const sl_gpio_t pa30 = { .port = SL_GPIO_PORT_A, .pin = 30 };
|
||||
const sl_gpio_t pa31 = { .port = SL_GPIO_PORT_A, .pin = 31 };
|
||||
|
||||
const sl_gpio_t pb0 = { .port = SL_GPIO_PORT_B, .pin = 0 };
|
||||
const sl_gpio_t pb1 = { .port = SL_GPIO_PORT_B, .pin = 1 };
|
||||
const sl_gpio_t pb2 = { .port = SL_GPIO_PORT_B, .pin = 2 };
|
||||
const sl_gpio_t pb3 = { .port = SL_GPIO_PORT_B, .pin = 3 };
|
||||
const sl_gpio_t pb4 = { .port = SL_GPIO_PORT_B, .pin = 4 };
|
||||
const sl_gpio_t pb5 = { .port = SL_GPIO_PORT_B, .pin = 5 };
|
||||
const sl_gpio_t pb6 = { .port = SL_GPIO_PORT_B, .pin = 6 };
|
||||
const sl_gpio_t pb7 = { .port = SL_GPIO_PORT_B, .pin = 7 };
|
||||
const sl_gpio_t pb8 = { .port = SL_GPIO_PORT_B, .pin = 8 };
|
||||
const sl_gpio_t pb9 = { .port = SL_GPIO_PORT_B, .pin = 9 };
|
||||
const sl_gpio_t pb10 = { .port = SL_GPIO_PORT_B, .pin = 10 };
|
||||
const sl_gpio_t pb11 = { .port = SL_GPIO_PORT_B, .pin = 11 };
|
||||
const sl_gpio_t pb12 = { .port = SL_GPIO_PORT_B, .pin = 12 };
|
||||
const sl_gpio_t pb13 = { .port = SL_GPIO_PORT_B, .pin = 13 };
|
||||
const sl_gpio_t pb14 = { .port = SL_GPIO_PORT_B, .pin = 14 };
|
||||
const sl_gpio_t pb15 = { .port = SL_GPIO_PORT_B, .pin = 15 };
|
||||
const sl_gpio_t pb16 = { .port = SL_GPIO_PORT_B, .pin = 16 };
|
||||
const sl_gpio_t pb17 = { .port = SL_GPIO_PORT_B, .pin = 17 };
|
||||
const sl_gpio_t pb18 = { .port = SL_GPIO_PORT_B, .pin = 18 };
|
||||
const sl_gpio_t pb19 = { .port = SL_GPIO_PORT_B, .pin = 19 };
|
||||
const sl_gpio_t pb20 = { .port = SL_GPIO_PORT_B, .pin = 20 };
|
||||
const sl_gpio_t pb21 = { .port = SL_GPIO_PORT_B, .pin = 21 };
|
||||
const sl_gpio_t pb22 = { .port = SL_GPIO_PORT_B, .pin = 22 };
|
||||
const sl_gpio_t pb23 = { .port = SL_GPIO_PORT_B, .pin = 23 };
|
||||
const sl_gpio_t pb24 = { .port = SL_GPIO_PORT_B, .pin = 24 };
|
||||
const sl_gpio_t pb25 = { .port = SL_GPIO_PORT_B, .pin = 25 };
|
||||
const sl_gpio_t pb26 = { .port = SL_GPIO_PORT_B, .pin = 26 };
|
||||
const sl_gpio_t pb27 = { .port = SL_GPIO_PORT_B, .pin = 27 };
|
||||
const sl_gpio_t pb28 = { .port = SL_GPIO_PORT_B, .pin = 28 };
|
||||
const sl_gpio_t pb29 = { .port = SL_GPIO_PORT_B, .pin = 29 };
|
||||
const sl_gpio_t pb30 = { .port = SL_GPIO_PORT_B, .pin = 30 };
|
||||
const sl_gpio_t pb31 = { .port = SL_GPIO_PORT_B, .pin = 31 };
|
||||
|
||||
const sl_gpio_t pc0 = { .port = SL_GPIO_PORT_C, .pin = 0 };
|
||||
const sl_gpio_t pc1 = { .port = SL_GPIO_PORT_C, .pin = 1 };
|
||||
const sl_gpio_t pc2 = { .port = SL_GPIO_PORT_C, .pin = 2 };
|
||||
const sl_gpio_t pc3 = { .port = SL_GPIO_PORT_C, .pin = 3 };
|
||||
const sl_gpio_t pc4 = { .port = SL_GPIO_PORT_C, .pin = 4 };
|
||||
const sl_gpio_t pc5 = { .port = SL_GPIO_PORT_C, .pin = 5 };
|
||||
const sl_gpio_t pc6 = { .port = SL_GPIO_PORT_C, .pin = 6 };
|
||||
const sl_gpio_t pc7 = { .port = SL_GPIO_PORT_C, .pin = 7 };
|
||||
const sl_gpio_t pc8 = { .port = SL_GPIO_PORT_C, .pin = 8 };
|
||||
const sl_gpio_t pc9 = { .port = SL_GPIO_PORT_C, .pin = 9 };
|
||||
const sl_gpio_t pc10 = { .port = SL_GPIO_PORT_C, .pin = 10 };
|
||||
const sl_gpio_t pc11 = { .port = SL_GPIO_PORT_C, .pin = 11 };
|
||||
const sl_gpio_t pc12 = { .port = SL_GPIO_PORT_C, .pin = 12 };
|
||||
const sl_gpio_t pc13 = { .port = SL_GPIO_PORT_C, .pin = 13 };
|
||||
const sl_gpio_t pc14 = { .port = SL_GPIO_PORT_C, .pin = 14 };
|
||||
const sl_gpio_t pc15 = { .port = SL_GPIO_PORT_C, .pin = 15 };
|
||||
const sl_gpio_t pc16 = { .port = SL_GPIO_PORT_C, .pin = 16 };
|
||||
const sl_gpio_t pc17 = { .port = SL_GPIO_PORT_C, .pin = 17 };
|
||||
const sl_gpio_t pc18 = { .port = SL_GPIO_PORT_C, .pin = 18 };
|
||||
const sl_gpio_t pc19 = { .port = SL_GPIO_PORT_C, .pin = 19 };
|
||||
const sl_gpio_t pc20 = { .port = SL_GPIO_PORT_C, .pin = 20 };
|
||||
const sl_gpio_t pc21 = { .port = SL_GPIO_PORT_C, .pin = 21 };
|
||||
const sl_gpio_t pc22 = { .port = SL_GPIO_PORT_C, .pin = 22 };
|
||||
const sl_gpio_t pc23 = { .port = SL_GPIO_PORT_C, .pin = 23 };
|
||||
const sl_gpio_t pc24 = { .port = SL_GPIO_PORT_C, .pin = 24 };
|
||||
const sl_gpio_t pc25 = { .port = SL_GPIO_PORT_C, .pin = 25 };
|
||||
const sl_gpio_t pc26 = { .port = SL_GPIO_PORT_C, .pin = 26 };
|
||||
const sl_gpio_t pc27 = { .port = SL_GPIO_PORT_C, .pin = 27 };
|
||||
const sl_gpio_t pc28 = { .port = SL_GPIO_PORT_C, .pin = 28 };
|
||||
const sl_gpio_t pc29 = { .port = SL_GPIO_PORT_C, .pin = 29 };
|
||||
const sl_gpio_t pc30 = { .port = SL_GPIO_PORT_C, .pin = 30 };
|
||||
const sl_gpio_t pc31 = { .port = SL_GPIO_PORT_C, .pin = 31 };
|
||||
|
||||
const sl_gpio_t pd0 = { .port = SL_GPIO_PORT_D, .pin = 0 };
|
||||
const sl_gpio_t pd1 = { .port = SL_GPIO_PORT_D, .pin = 1 };
|
||||
const sl_gpio_t pd2 = { .port = SL_GPIO_PORT_D, .pin = 2 };
|
||||
const sl_gpio_t pd3 = { .port = SL_GPIO_PORT_D, .pin = 3 };
|
||||
const sl_gpio_t pd4 = { .port = SL_GPIO_PORT_D, .pin = 4 };
|
||||
const sl_gpio_t pd5 = { .port = SL_GPIO_PORT_D, .pin = 5 };
|
||||
const sl_gpio_t pd6 = { .port = SL_GPIO_PORT_D, .pin = 6 };
|
||||
const sl_gpio_t pd7 = { .port = SL_GPIO_PORT_D, .pin = 7 };
|
||||
const sl_gpio_t pd8 = { .port = SL_GPIO_PORT_D, .pin = 8 };
|
||||
const sl_gpio_t pd9 = { .port = SL_GPIO_PORT_D, .pin = 9 };
|
||||
const sl_gpio_t pd10 = { .port = SL_GPIO_PORT_D, .pin = 10 };
|
||||
const sl_gpio_t pd11 = { .port = SL_GPIO_PORT_D, .pin = 11 };
|
||||
const sl_gpio_t pd12 = { .port = SL_GPIO_PORT_D, .pin = 12 };
|
||||
const sl_gpio_t pd13 = { .port = SL_GPIO_PORT_D, .pin = 13 };
|
||||
const sl_gpio_t pd14 = { .port = SL_GPIO_PORT_D, .pin = 14 };
|
||||
const sl_gpio_t pd15 = { .port = SL_GPIO_PORT_D, .pin = 15 };
|
||||
const sl_gpio_t pd16 = { .port = SL_GPIO_PORT_D, .pin = 16 };
|
||||
const sl_gpio_t pd17 = { .port = SL_GPIO_PORT_D, .pin = 17 };
|
||||
const sl_gpio_t pd18 = { .port = SL_GPIO_PORT_D, .pin = 18 };
|
||||
const sl_gpio_t pd19 = { .port = SL_GPIO_PORT_D, .pin = 19 };
|
||||
const sl_gpio_t pd20 = { .port = SL_GPIO_PORT_D, .pin = 20 };
|
||||
const sl_gpio_t pd21 = { .port = SL_GPIO_PORT_D, .pin = 21 };
|
||||
const sl_gpio_t pd22 = { .port = SL_GPIO_PORT_D, .pin = 22 };
|
||||
const sl_gpio_t pd23 = { .port = SL_GPIO_PORT_D, .pin = 23 };
|
||||
const sl_gpio_t pd24 = { .port = SL_GPIO_PORT_D, .pin = 24 };
|
||||
const sl_gpio_t pd25 = { .port = SL_GPIO_PORT_D, .pin = 25 };
|
||||
const sl_gpio_t pd26 = { .port = SL_GPIO_PORT_D, .pin = 26 };
|
||||
const sl_gpio_t pd27 = { .port = SL_GPIO_PORT_D, .pin = 27 };
|
||||
const sl_gpio_t pd28 = { .port = SL_GPIO_PORT_D, .pin = 28 };
|
||||
const sl_gpio_t pd29 = { .port = SL_GPIO_PORT_D, .pin = 29 };
|
||||
const sl_gpio_t pd30 = { .port = SL_GPIO_PORT_D, .pin = 30 };
|
||||
const sl_gpio_t pd31 = { .port = SL_GPIO_PORT_D, .pin = 31 };
|
||||
|
||||
const sl_gpio_t pe0 = { .port = SL_GPIO_PORT_E, .pin = 0 };
|
||||
const sl_gpio_t pe1 = { .port = SL_GPIO_PORT_E, .pin = 1 };
|
||||
const sl_gpio_t pe2 = { .port = SL_GPIO_PORT_E, .pin = 2 };
|
||||
const sl_gpio_t pe3 = { .port = SL_GPIO_PORT_E, .pin = 3 };
|
||||
const sl_gpio_t pe4 = { .port = SL_GPIO_PORT_E, .pin = 4 };
|
||||
const sl_gpio_t pe5 = { .port = SL_GPIO_PORT_E, .pin = 5 };
|
||||
const sl_gpio_t pe6 = { .port = SL_GPIO_PORT_E, .pin = 6 };
|
||||
const sl_gpio_t pe7 = { .port = SL_GPIO_PORT_E, .pin = 7 };
|
||||
const sl_gpio_t pe8 = { .port = SL_GPIO_PORT_E, .pin = 8 };
|
||||
const sl_gpio_t pe9 = { .port = SL_GPIO_PORT_E, .pin = 9 };
|
||||
const sl_gpio_t pe10 = { .port = SL_GPIO_PORT_E, .pin = 10 };
|
||||
const sl_gpio_t pe11 = { .port = SL_GPIO_PORT_E, .pin = 11 };
|
||||
const sl_gpio_t pe12 = { .port = SL_GPIO_PORT_E, .pin = 12 };
|
||||
const sl_gpio_t pe13 = { .port = SL_GPIO_PORT_E, .pin = 13 };
|
||||
const sl_gpio_t pe14 = { .port = SL_GPIO_PORT_E, .pin = 14 };
|
||||
const sl_gpio_t pe15 = { .port = SL_GPIO_PORT_E, .pin = 15 };
|
||||
const sl_gpio_t pe16 = { .port = SL_GPIO_PORT_E, .pin = 16 };
|
||||
const sl_gpio_t pe17 = { .port = SL_GPIO_PORT_E, .pin = 17 };
|
||||
const sl_gpio_t pe18 = { .port = SL_GPIO_PORT_E, .pin = 18 };
|
||||
const sl_gpio_t pe19 = { .port = SL_GPIO_PORT_E, .pin = 19 };
|
||||
const sl_gpio_t pe20 = { .port = SL_GPIO_PORT_E, .pin = 20 };
|
||||
const sl_gpio_t pe21 = { .port = SL_GPIO_PORT_E, .pin = 21 };
|
||||
const sl_gpio_t pe22 = { .port = SL_GPIO_PORT_E, .pin = 22 };
|
||||
const sl_gpio_t pe23 = { .port = SL_GPIO_PORT_E, .pin = 23 };
|
||||
const sl_gpio_t pe24 = { .port = SL_GPIO_PORT_E, .pin = 24 };
|
||||
const sl_gpio_t pe25 = { .port = SL_GPIO_PORT_E, .pin = 25 };
|
||||
const sl_gpio_t pe26 = { .port = SL_GPIO_PORT_E, .pin = 26 };
|
||||
const sl_gpio_t pe27 = { .port = SL_GPIO_PORT_E, .pin = 27 };
|
||||
const sl_gpio_t pe28 = { .port = SL_GPIO_PORT_E, .pin = 28 };
|
||||
const sl_gpio_t pe29 = { .port = SL_GPIO_PORT_E, .pin = 29 };
|
||||
const sl_gpio_t pe30 = { .port = SL_GPIO_PORT_E, .pin = 30 };
|
||||
const sl_gpio_t pe31 = { .port = SL_GPIO_PORT_E, .pin = 31 };
|
||||
|
||||
const sl_gpio_t pf0 = { .port = SL_GPIO_PORT_F, .pin = 0 };
|
||||
const sl_gpio_t pf1 = { .port = SL_GPIO_PORT_F, .pin = 1 };
|
||||
const sl_gpio_t pf2 = { .port = SL_GPIO_PORT_F, .pin = 2 };
|
||||
const sl_gpio_t pf3 = { .port = SL_GPIO_PORT_F, .pin = 3 };
|
||||
const sl_gpio_t pf4 = { .port = SL_GPIO_PORT_F, .pin = 4 };
|
||||
const sl_gpio_t pf5 = { .port = SL_GPIO_PORT_F, .pin = 5 };
|
||||
const sl_gpio_t pf6 = { .port = SL_GPIO_PORT_F, .pin = 6 };
|
||||
const sl_gpio_t pf7 = { .port = SL_GPIO_PORT_F, .pin = 7 };
|
||||
const sl_gpio_t pf8 = { .port = SL_GPIO_PORT_F, .pin = 8 };
|
||||
const sl_gpio_t pf9 = { .port = SL_GPIO_PORT_F, .pin = 9 };
|
||||
const sl_gpio_t pf10 = { .port = SL_GPIO_PORT_F, .pin = 10 };
|
||||
const sl_gpio_t pf11 = { .port = SL_GPIO_PORT_F, .pin = 11 };
|
||||
const sl_gpio_t pf12 = { .port = SL_GPIO_PORT_F, .pin = 12 };
|
||||
const sl_gpio_t pf13 = { .port = SL_GPIO_PORT_F, .pin = 13 };
|
||||
const sl_gpio_t pf14 = { .port = SL_GPIO_PORT_F, .pin = 14 };
|
||||
const sl_gpio_t pf15 = { .port = SL_GPIO_PORT_F, .pin = 15 };
|
||||
const sl_gpio_t pf16 = { .port = SL_GPIO_PORT_F, .pin = 16 };
|
||||
const sl_gpio_t pf17 = { .port = SL_GPIO_PORT_F, .pin = 17 };
|
||||
const sl_gpio_t pf18 = { .port = SL_GPIO_PORT_F, .pin = 18 };
|
||||
const sl_gpio_t pf19 = { .port = SL_GPIO_PORT_F, .pin = 19 };
|
||||
const sl_gpio_t pf20 = { .port = SL_GPIO_PORT_F, .pin = 20 };
|
||||
const sl_gpio_t pf21 = { .port = SL_GPIO_PORT_F, .pin = 21 };
|
||||
const sl_gpio_t pf22 = { .port = SL_GPIO_PORT_F, .pin = 22 };
|
||||
const sl_gpio_t pf23 = { .port = SL_GPIO_PORT_F, .pin = 23 };
|
||||
const sl_gpio_t pf24 = { .port = SL_GPIO_PORT_F, .pin = 24 };
|
||||
const sl_gpio_t pf25 = { .port = SL_GPIO_PORT_F, .pin = 25 };
|
||||
const sl_gpio_t pf26 = { .port = SL_GPIO_PORT_F, .pin = 26 };
|
||||
const sl_gpio_t pf27 = { .port = SL_GPIO_PORT_F, .pin = 27 };
|
||||
const sl_gpio_t pf28 = { .port = SL_GPIO_PORT_F, .pin = 28 };
|
||||
const sl_gpio_t pf29 = { .port = SL_GPIO_PORT_F, .pin = 29 };
|
||||
const sl_gpio_t pf30 = { .port = SL_GPIO_PORT_F, .pin = 30 };
|
||||
const sl_gpio_t pf31 = { .port = SL_GPIO_PORT_F, .pin = 31 };
|
||||
|
||||
const sl_gpio_t pg0 = { .port = SL_GPIO_PORT_G, .pin = 0 };
|
||||
const sl_gpio_t pg1 = { .port = SL_GPIO_PORT_G, .pin = 1 };
|
||||
const sl_gpio_t pg2 = { .port = SL_GPIO_PORT_G, .pin = 2 };
|
||||
const sl_gpio_t pg3 = { .port = SL_GPIO_PORT_G, .pin = 3 };
|
||||
const sl_gpio_t pg4 = { .port = SL_GPIO_PORT_G, .pin = 4 };
|
||||
const sl_gpio_t pg5 = { .port = SL_GPIO_PORT_G, .pin = 5 };
|
||||
const sl_gpio_t pg6 = { .port = SL_GPIO_PORT_G, .pin = 6 };
|
||||
const sl_gpio_t pg7 = { .port = SL_GPIO_PORT_G, .pin = 7 };
|
||||
const sl_gpio_t pg8 = { .port = SL_GPIO_PORT_G, .pin = 8 };
|
||||
const sl_gpio_t pg9 = { .port = SL_GPIO_PORT_G, .pin = 9 };
|
||||
const sl_gpio_t pg10 = { .port = SL_GPIO_PORT_G, .pin = 10 };
|
||||
const sl_gpio_t pg11 = { .port = SL_GPIO_PORT_G, .pin = 11 };
|
||||
const sl_gpio_t pg12 = { .port = SL_GPIO_PORT_G, .pin = 12 };
|
||||
const sl_gpio_t pg13 = { .port = SL_GPIO_PORT_G, .pin = 13 };
|
||||
const sl_gpio_t pg14 = { .port = SL_GPIO_PORT_G, .pin = 14 };
|
||||
const sl_gpio_t pg15 = { .port = SL_GPIO_PORT_G, .pin = 15 };
|
||||
const sl_gpio_t pg16 = { .port = SL_GPIO_PORT_G, .pin = 16 };
|
||||
const sl_gpio_t pg17 = { .port = SL_GPIO_PORT_G, .pin = 17 };
|
||||
const sl_gpio_t pg18 = { .port = SL_GPIO_PORT_G, .pin = 18 };
|
||||
const sl_gpio_t pg19 = { .port = SL_GPIO_PORT_G, .pin = 19 };
|
||||
const sl_gpio_t pg20 = { .port = SL_GPIO_PORT_G, .pin = 20 };
|
||||
const sl_gpio_t pg21 = { .port = SL_GPIO_PORT_G, .pin = 21 };
|
||||
const sl_gpio_t pg22 = { .port = SL_GPIO_PORT_G, .pin = 22 };
|
||||
const sl_gpio_t pg23 = { .port = SL_GPIO_PORT_G, .pin = 23 };
|
||||
const sl_gpio_t pg24 = { .port = SL_GPIO_PORT_G, .pin = 24 };
|
||||
const sl_gpio_t pg25 = { .port = SL_GPIO_PORT_G, .pin = 25 };
|
||||
const sl_gpio_t pg26 = { .port = SL_GPIO_PORT_G, .pin = 26 };
|
||||
const sl_gpio_t pg27 = { .port = SL_GPIO_PORT_G, .pin = 27 };
|
||||
const sl_gpio_t pg28 = { .port = SL_GPIO_PORT_G, .pin = 28 };
|
||||
const sl_gpio_t pg29 = { .port = SL_GPIO_PORT_G, .pin = 29 };
|
||||
const sl_gpio_t pg30 = { .port = SL_GPIO_PORT_G, .pin = 30 };
|
||||
const sl_gpio_t pg31 = { .port = SL_GPIO_PORT_G, .pin = 31 };
|
||||
|
||||
const sl_gpio_t ph0 = { .port = SL_GPIO_PORT_H, .pin = 0 };
|
||||
const sl_gpio_t ph1 = { .port = SL_GPIO_PORT_H, .pin = 1 };
|
||||
const sl_gpio_t ph2 = { .port = SL_GPIO_PORT_H, .pin = 2 };
|
||||
const sl_gpio_t ph3 = { .port = SL_GPIO_PORT_H, .pin = 3 };
|
||||
const sl_gpio_t ph4 = { .port = SL_GPIO_PORT_H, .pin = 4 };
|
||||
const sl_gpio_t ph5 = { .port = SL_GPIO_PORT_H, .pin = 5 };
|
||||
const sl_gpio_t ph6 = { .port = SL_GPIO_PORT_H, .pin = 6 };
|
||||
const sl_gpio_t ph7 = { .port = SL_GPIO_PORT_H, .pin = 7 };
|
||||
const sl_gpio_t ph8 = { .port = SL_GPIO_PORT_H, .pin = 8 };
|
||||
const sl_gpio_t ph9 = { .port = SL_GPIO_PORT_H, .pin = 9 };
|
||||
const sl_gpio_t ph10 = { .port = SL_GPIO_PORT_H, .pin = 10 };
|
||||
const sl_gpio_t ph11 = { .port = SL_GPIO_PORT_H, .pin = 11 };
|
||||
const sl_gpio_t ph12 = { .port = SL_GPIO_PORT_H, .pin = 12 };
|
||||
const sl_gpio_t ph13 = { .port = SL_GPIO_PORT_H, .pin = 13 };
|
||||
const sl_gpio_t ph14 = { .port = SL_GPIO_PORT_H, .pin = 14 };
|
||||
const sl_gpio_t ph15 = { .port = SL_GPIO_PORT_H, .pin = 15 };
|
||||
const sl_gpio_t ph16 = { .port = SL_GPIO_PORT_H, .pin = 16 };
|
||||
const sl_gpio_t ph17 = { .port = SL_GPIO_PORT_H, .pin = 17 };
|
||||
const sl_gpio_t ph18 = { .port = SL_GPIO_PORT_H, .pin = 18 };
|
||||
const sl_gpio_t ph19 = { .port = SL_GPIO_PORT_H, .pin = 19 };
|
||||
const sl_gpio_t ph20 = { .port = SL_GPIO_PORT_H, .pin = 20 };
|
||||
const sl_gpio_t ph21 = { .port = SL_GPIO_PORT_H, .pin = 21 };
|
||||
const sl_gpio_t ph22 = { .port = SL_GPIO_PORT_H, .pin = 22 };
|
||||
const sl_gpio_t ph23 = { .port = SL_GPIO_PORT_H, .pin = 23 };
|
||||
const sl_gpio_t ph24 = { .port = SL_GPIO_PORT_H, .pin = 24 };
|
||||
const sl_gpio_t ph25 = { .port = SL_GPIO_PORT_H, .pin = 25 };
|
||||
const sl_gpio_t ph26 = { .port = SL_GPIO_PORT_H, .pin = 26 };
|
||||
const sl_gpio_t ph27 = { .port = SL_GPIO_PORT_H, .pin = 27 };
|
||||
const sl_gpio_t ph28 = { .port = SL_GPIO_PORT_H, .pin = 28 };
|
||||
const sl_gpio_t ph29 = { .port = SL_GPIO_PORT_H, .pin = 29 };
|
||||
const sl_gpio_t ph30 = { .port = SL_GPIO_PORT_H, .pin = 30 };
|
||||
const sl_gpio_t ph31 = { .port = SL_GPIO_PORT_H, .pin = 31 };
|
||||
|
||||
const sl_gpio_t pi0 = { .port = SL_GPIO_PORT_I, .pin = 0 };
|
||||
const sl_gpio_t pi1 = { .port = SL_GPIO_PORT_I, .pin = 1 };
|
||||
const sl_gpio_t pi2 = { .port = SL_GPIO_PORT_I, .pin = 2 };
|
||||
const sl_gpio_t pi3 = { .port = SL_GPIO_PORT_I, .pin = 3 };
|
||||
const sl_gpio_t pi4 = { .port = SL_GPIO_PORT_I, .pin = 4 };
|
||||
const sl_gpio_t pi5 = { .port = SL_GPIO_PORT_I, .pin = 5 };
|
||||
const sl_gpio_t pi6 = { .port = SL_GPIO_PORT_I, .pin = 6 };
|
||||
const sl_gpio_t pi7 = { .port = SL_GPIO_PORT_I, .pin = 7 };
|
||||
const sl_gpio_t pi8 = { .port = SL_GPIO_PORT_I, .pin = 8 };
|
||||
const sl_gpio_t pi9 = { .port = SL_GPIO_PORT_I, .pin = 9 };
|
||||
const sl_gpio_t pi10 = { .port = SL_GPIO_PORT_I, .pin = 10 };
|
||||
const sl_gpio_t pi11 = { .port = SL_GPIO_PORT_I, .pin = 11 };
|
||||
const sl_gpio_t pi12 = { .port = SL_GPIO_PORT_I, .pin = 12 };
|
||||
const sl_gpio_t pi13 = { .port = SL_GPIO_PORT_I, .pin = 13 };
|
||||
const sl_gpio_t pi14 = { .port = SL_GPIO_PORT_I, .pin = 14 };
|
||||
const sl_gpio_t pi15 = { .port = SL_GPIO_PORT_I, .pin = 15 };
|
||||
const sl_gpio_t pi16 = { .port = SL_GPIO_PORT_I, .pin = 16 };
|
||||
const sl_gpio_t pi17 = { .port = SL_GPIO_PORT_I, .pin = 17 };
|
||||
const sl_gpio_t pi18 = { .port = SL_GPIO_PORT_I, .pin = 18 };
|
||||
const sl_gpio_t pi19 = { .port = SL_GPIO_PORT_I, .pin = 19 };
|
||||
const sl_gpio_t pi20 = { .port = SL_GPIO_PORT_I, .pin = 20 };
|
||||
const sl_gpio_t pi21 = { .port = SL_GPIO_PORT_I, .pin = 21 };
|
||||
const sl_gpio_t pi22 = { .port = SL_GPIO_PORT_I, .pin = 22 };
|
||||
const sl_gpio_t pi23 = { .port = SL_GPIO_PORT_I, .pin = 23 };
|
||||
const sl_gpio_t pi24 = { .port = SL_GPIO_PORT_I, .pin = 24 };
|
||||
const sl_gpio_t pi25 = { .port = SL_GPIO_PORT_I, .pin = 25 };
|
||||
const sl_gpio_t pi26 = { .port = SL_GPIO_PORT_I, .pin = 26 };
|
||||
const sl_gpio_t pi27 = { .port = SL_GPIO_PORT_I, .pin = 27 };
|
||||
const sl_gpio_t pi28 = { .port = SL_GPIO_PORT_I, .pin = 28 };
|
||||
const sl_gpio_t pi29 = { .port = SL_GPIO_PORT_I, .pin = 29 };
|
||||
const sl_gpio_t pi30 = { .port = SL_GPIO_PORT_I, .pin = 30 };
|
||||
const sl_gpio_t pi31 = { .port = SL_GPIO_PORT_I, .pin = 31 };
|
||||
|
||||
const sl_gpio_t pj0 = { .port = SL_GPIO_PORT_J, .pin = 0 };
|
||||
const sl_gpio_t pj1 = { .port = SL_GPIO_PORT_J, .pin = 1 };
|
||||
const sl_gpio_t pj2 = { .port = SL_GPIO_PORT_J, .pin = 2 };
|
||||
const sl_gpio_t pj3 = { .port = SL_GPIO_PORT_J, .pin = 3 };
|
||||
const sl_gpio_t pj4 = { .port = SL_GPIO_PORT_J, .pin = 4 };
|
||||
const sl_gpio_t pj5 = { .port = SL_GPIO_PORT_J, .pin = 5 };
|
||||
const sl_gpio_t pj6 = { .port = SL_GPIO_PORT_J, .pin = 6 };
|
||||
const sl_gpio_t pj7 = { .port = SL_GPIO_PORT_J, .pin = 7 };
|
||||
const sl_gpio_t pj8 = { .port = SL_GPIO_PORT_J, .pin = 8 };
|
||||
const sl_gpio_t pj9 = { .port = SL_GPIO_PORT_J, .pin = 9 };
|
||||
const sl_gpio_t pj10 = { .port = SL_GPIO_PORT_J, .pin = 10 };
|
||||
const sl_gpio_t pj11 = { .port = SL_GPIO_PORT_J, .pin = 11 };
|
||||
const sl_gpio_t pj12 = { .port = SL_GPIO_PORT_J, .pin = 12 };
|
||||
const sl_gpio_t pj13 = { .port = SL_GPIO_PORT_J, .pin = 13 };
|
||||
const sl_gpio_t pj14 = { .port = SL_GPIO_PORT_J, .pin = 14 };
|
||||
const sl_gpio_t pj15 = { .port = SL_GPIO_PORT_J, .pin = 15 };
|
||||
const sl_gpio_t pj16 = { .port = SL_GPIO_PORT_J, .pin = 16 };
|
||||
const sl_gpio_t pj17 = { .port = SL_GPIO_PORT_J, .pin = 17 };
|
||||
const sl_gpio_t pj18 = { .port = SL_GPIO_PORT_J, .pin = 18 };
|
||||
const sl_gpio_t pj19 = { .port = SL_GPIO_PORT_J, .pin = 19 };
|
||||
const sl_gpio_t pj20 = { .port = SL_GPIO_PORT_J, .pin = 20 };
|
||||
const sl_gpio_t pj21 = { .port = SL_GPIO_PORT_J, .pin = 21 };
|
||||
const sl_gpio_t pj22 = { .port = SL_GPIO_PORT_J, .pin = 22 };
|
||||
const sl_gpio_t pj23 = { .port = SL_GPIO_PORT_J, .pin = 23 };
|
||||
const sl_gpio_t pj24 = { .port = SL_GPIO_PORT_J, .pin = 24 };
|
||||
const sl_gpio_t pj25 = { .port = SL_GPIO_PORT_J, .pin = 25 };
|
||||
const sl_gpio_t pj26 = { .port = SL_GPIO_PORT_J, .pin = 26 };
|
||||
const sl_gpio_t pj27 = { .port = SL_GPIO_PORT_J, .pin = 27 };
|
||||
const sl_gpio_t pj28 = { .port = SL_GPIO_PORT_J, .pin = 28 };
|
||||
const sl_gpio_t pj29 = { .port = SL_GPIO_PORT_J, .pin = 29 };
|
||||
const sl_gpio_t pj30 = { .port = SL_GPIO_PORT_J, .pin = 30 };
|
||||
const sl_gpio_t pj31 = { .port = SL_GPIO_PORT_J, .pin = 31 };
|
||||
|
||||
const sl_gpio_t pk0 = { .port = SL_GPIO_PORT_K, .pin = 0 };
|
||||
const sl_gpio_t pk1 = { .port = SL_GPIO_PORT_K, .pin = 1 };
|
||||
const sl_gpio_t pk2 = { .port = SL_GPIO_PORT_K, .pin = 2 };
|
||||
const sl_gpio_t pk3 = { .port = SL_GPIO_PORT_K, .pin = 3 };
|
||||
const sl_gpio_t pk4 = { .port = SL_GPIO_PORT_K, .pin = 4 };
|
||||
const sl_gpio_t pk5 = { .port = SL_GPIO_PORT_K, .pin = 5 };
|
||||
const sl_gpio_t pk6 = { .port = SL_GPIO_PORT_K, .pin = 6 };
|
||||
const sl_gpio_t pk7 = { .port = SL_GPIO_PORT_K, .pin = 7 };
|
||||
const sl_gpio_t pk8 = { .port = SL_GPIO_PORT_K, .pin = 8 };
|
||||
const sl_gpio_t pk9 = { .port = SL_GPIO_PORT_K, .pin = 9 };
|
||||
const sl_gpio_t pk10 = { .port = SL_GPIO_PORT_K, .pin = 10 };
|
||||
const sl_gpio_t pk11 = { .port = SL_GPIO_PORT_K, .pin = 11 };
|
||||
const sl_gpio_t pk12 = { .port = SL_GPIO_PORT_K, .pin = 12 };
|
||||
const sl_gpio_t pk13 = { .port = SL_GPIO_PORT_K, .pin = 13 };
|
||||
const sl_gpio_t pk14 = { .port = SL_GPIO_PORT_K, .pin = 14 };
|
||||
const sl_gpio_t pk15 = { .port = SL_GPIO_PORT_K, .pin = 15 };
|
||||
const sl_gpio_t pk16 = { .port = SL_GPIO_PORT_K, .pin = 16 };
|
||||
const sl_gpio_t pk17 = { .port = SL_GPIO_PORT_K, .pin = 17 };
|
||||
const sl_gpio_t pk18 = { .port = SL_GPIO_PORT_K, .pin = 18 };
|
||||
const sl_gpio_t pk19 = { .port = SL_GPIO_PORT_K, .pin = 19 };
|
||||
const sl_gpio_t pk20 = { .port = SL_GPIO_PORT_K, .pin = 20 };
|
||||
const sl_gpio_t pk21 = { .port = SL_GPIO_PORT_K, .pin = 21 };
|
||||
const sl_gpio_t pk22 = { .port = SL_GPIO_PORT_K, .pin = 22 };
|
||||
const sl_gpio_t pk23 = { .port = SL_GPIO_PORT_K, .pin = 23 };
|
||||
const sl_gpio_t pk24 = { .port = SL_GPIO_PORT_K, .pin = 24 };
|
||||
const sl_gpio_t pk25 = { .port = SL_GPIO_PORT_K, .pin = 25 };
|
||||
const sl_gpio_t pk26 = { .port = SL_GPIO_PORT_K, .pin = 26 };
|
||||
const sl_gpio_t pk27 = { .port = SL_GPIO_PORT_K, .pin = 27 };
|
||||
const sl_gpio_t pk28 = { .port = SL_GPIO_PORT_K, .pin = 28 };
|
||||
const sl_gpio_t pk29 = { .port = SL_GPIO_PORT_K, .pin = 29 };
|
||||
const sl_gpio_t pk30 = { .port = SL_GPIO_PORT_K, .pin = 30 };
|
||||
const sl_gpio_t pk31 = { .port = SL_GPIO_PORT_K, .pin = 31 };
|
||||
|
||||
/** @} (end addtogroup device_gpio) */
|
||||
769
Libs/platform/service/device_manager/src/sl_device_peripheral.c
Normal file
769
Libs/platform/service/device_manager/src/sl_device_peripheral.c
Normal file
@@ -0,0 +1,769 @@
|
||||
/**************************************************************************//**
|
||||
* @file
|
||||
* @brief Device Manager API Definition
|
||||
******************************************************************************
|
||||
* # 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_device_peripheral.h"
|
||||
#include "sl_device_clock.h"
|
||||
#include "cmsis_compiler.h"
|
||||
#include "em_device.h"
|
||||
/***************************************************************************//**
|
||||
* Device Abstraction Peripheral default values.
|
||||
******************************************************************************/
|
||||
// Weak definition of peripheral ACMP0.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_acmp0 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral ACMP1.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_acmp1 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral ADC0.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_adc0 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral AES.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_aes = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral AMUXCP0.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_amuxcp0 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral BUFC.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_bufc = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral BURAM.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_buram = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral BURTC.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_burtc = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral CMU.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_cmu = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral CRYPTOACC.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_cryptoacc = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral DCDC.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_dcdc = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral DEVINFO.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_devinfo = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral DMEM.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_dmem = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral DMEM0.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_dmem0 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral DMEM1.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_dmem1 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral DPLL0.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_dpll0 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral EMU.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_emu = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral ETAMPDET.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_etampdet = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral EUART0.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_euart0 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral EUSART0.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_eusart0 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral EUSART1.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_eusart1 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral EUSART2.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_eusart2 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral EUSART3.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_eusart3 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral EUSART4.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_eusart4 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral FSRCO.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_fsrco = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral GPCRC0.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_gpcrc0 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral GPIO.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_gpio = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral HFRCO0.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_hfrco0 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral HFRCOEM23.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_hfrcoem23 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral HFXO0.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_hfxo0 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral HOSTMAILBOX.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_hostmailbox = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral HOSTPORTAL.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_hostportal = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral I2C0.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_i2c0 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral I2C1.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_i2c1 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral I2C2.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_i2c2 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral I2C3.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_i2c3 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral IADC0.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_iadc0 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral ICACHE0.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_icache0 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral KEYSCAN.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_keyscan = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral L1ICACHE0.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_l1icache0 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral L2ICACHE0.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_l2icache0 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral LCD.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_lcd = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral LCDRF.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_lcdrf = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral LDMA0.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_ldma0 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral LDMAXBAR0.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_ldmaxbar0 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral LEDDRV0.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_leddrv0 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral LESENSE.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_lesense = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral LETIMER0.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_letimer0 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral LFRCO.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_lfrco = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral LFXO.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_lfxo = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral LPWAES.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_lpwaes = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral LPW0PORTAL.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_lpw0portal = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral LVGD.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_lvgd = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral MPAHBRAM.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_mpahbram = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral MSC.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_msc = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral MVP.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_mvp = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral PCNT0.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_pcnt0 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral PDM.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_pdm = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral PFMXPPRF.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_pfmxpprf = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral PIXELRZ0.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_pixelrz0 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral PIXELRZ1.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_pixelrz1 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral PRORTC.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_prortc = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral PRS.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_prs = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral RADIOAES.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_radioaes = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral RFFPLL0.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_rffpll0 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral RPA.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_rpa = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral RTCC.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_rtcc = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral SCRATCHPAD.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_scratchpad = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral SEMAILBOX.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_semailbox = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral SEMAPHORE0.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_semaphore0 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral SEMAPHORE1.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_semaphore1 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral SEPORTAL.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_seportal = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral SEPUF.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_sepuf = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral SMU.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_smu = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral SOCPLL0.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_socpll0 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral SYMCRYPTO.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_symcrypto = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral SYSCFG.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_syscfg = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral SYSRTC0.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_sysrtc0 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral TIMER0.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_timer0 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral TIMER1.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_timer1 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral TIMER2.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_timer2 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral TIMER3.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_timer3 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral TIMER4.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_timer4 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral TIMER5.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_timer5 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral TIMER6.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_timer6 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral TIMER7.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_timer7 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral TIMER8.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_timer8 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral TIMER9.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_timer9 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral ULFRCO.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_ulfrco = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral USART0.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_usart0 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral USART1.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_usart1 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral USART2.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_usart2 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral USB.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_usb = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral USBAHB.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_usbahb = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral USBPLL0.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_usbpll0 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral VDAC0.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_vdac0 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral VDAC1.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_vdac1 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral WDOG0.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_wdog0 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
// Weak definition of peripheral WDOG1.
|
||||
__WEAK const sl_peripheral_val_t sl_peripheral_val_wdog1 = { .base = 0xFFFFFFFF,
|
||||
.clk_branch = SL_CLOCK_BRANCH_INVALID,
|
||||
.bus_clock = SL_BUS_CLOCK_INVALID };
|
||||
|
||||
#if defined(__ICCARM__)
|
||||
// Disable IAR multiple typedefs declaration warning.
|
||||
#pragma diag_suppress=Pe301
|
||||
#endif
|
||||
|
||||
// External base address getter declaration for ACMP.
|
||||
extern ACMP_TypeDef *sl_device_peripheral_acmp_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for ADC.
|
||||
extern ADC_TypeDef *sl_device_peripheral_adc_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for AES.
|
||||
extern AES_TypeDef *sl_device_peripheral_aes_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for AMUXCP.
|
||||
extern AMUXCP_TypeDef *sl_device_peripheral_amuxcp_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for BUFC.
|
||||
extern BUFC_TypeDef *sl_device_peripheral_bufc_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for BURAM.
|
||||
extern BURAM_TypeDef *sl_device_peripheral_buram_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for BURTC.
|
||||
extern BURTC_TypeDef *sl_device_peripheral_burtc_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for CMU.
|
||||
extern CMU_TypeDef *sl_device_peripheral_cmu_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for CRYPTOACC.
|
||||
extern CRYPTOACC_TypeDef *sl_device_peripheral_cryptoacc_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for CRYPTOACC_PKCTRL.
|
||||
extern CRYPTOACC_PKCTRL_TypeDef *sl_device_peripheral_cryptoacc_pkctrl_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for CRYPTOACC_RNGCTRL.
|
||||
extern CRYPTOACC_RNGCTRL_TypeDef *sl_device_peripheral_cryptoacc_rngctrl_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for DCDC.
|
||||
extern DCDC_TypeDef *sl_device_peripheral_dcdc_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for DEVINFO.
|
||||
extern DEVINFO_TypeDef *sl_device_peripheral_devinfo_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for DPLL.
|
||||
extern DPLL_TypeDef *sl_device_peripheral_dpll_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for EMU.
|
||||
extern EMU_TypeDef *sl_device_peripheral_emu_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for EMU_CFGNS.
|
||||
extern EMU_CFGNS_TypeDef *sl_device_peripheral_emu_cfgns_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for ETAMPDET.
|
||||
extern ETAMPDET_TypeDef *sl_device_peripheral_etampdet_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for EUSART.
|
||||
extern EUSART_TypeDef *sl_device_peripheral_eusart_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for FSRCO.
|
||||
extern FSRCO_TypeDef *sl_device_peripheral_fsrco_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for GPCRC.
|
||||
extern GPCRC_TypeDef *sl_device_peripheral_gpcrc_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for GPIO.
|
||||
extern GPIO_TypeDef *sl_device_peripheral_gpio_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for HFRCO.
|
||||
extern HFRCO_TypeDef *sl_device_peripheral_hfrco_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for HFXO.
|
||||
extern HFXO_TypeDef *sl_device_peripheral_hfxo_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for HOSTPORTAL.
|
||||
extern HOSTPORTAL_TypeDef *sl_device_peripheral_hostportal_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for HYDRARAM.
|
||||
extern HYDRARAM_TypeDef *sl_device_peripheral_hydraram_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for I2C.
|
||||
extern I2C_TypeDef *sl_device_peripheral_i2c_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for IADC.
|
||||
extern IADC_TypeDef *sl_device_peripheral_iadc_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for ICACHE.
|
||||
extern ICACHE_TypeDef *sl_device_peripheral_icache_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for KEYSCAN.
|
||||
extern KEYSCAN_TypeDef *sl_device_peripheral_keyscan_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for L2CACHE.
|
||||
extern L2CACHE_TypeDef *sl_device_peripheral_l2cache_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for LCD.
|
||||
extern LCD_TypeDef *sl_device_peripheral_lcd_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for LCDRF.
|
||||
extern LCDRF_TypeDef *sl_device_peripheral_lcdrf_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for LDMA.
|
||||
extern LDMA_TypeDef *sl_device_peripheral_ldma_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for LDMAXBAR.
|
||||
extern LDMAXBAR_TypeDef *sl_device_peripheral_ldmaxbar_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for LEDDRV.
|
||||
extern LEDDRV_TypeDef *sl_device_peripheral_leddrv_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for LESENSE.
|
||||
extern LESENSE_TypeDef *sl_device_peripheral_lesense_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for LETIMER.
|
||||
extern LETIMER_TypeDef *sl_device_peripheral_letimer_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for LFRCO.
|
||||
extern LFRCO_TypeDef *sl_device_peripheral_lfrco_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for LFXO.
|
||||
extern LFXO_TypeDef *sl_device_peripheral_lfxo_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for LPWAES.
|
||||
extern LPWAES_TypeDef *sl_device_peripheral_lpwaes_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for LPW0PORTAL.
|
||||
extern LPW0PORTAL_TypeDef *sl_device_peripheral_lpw0portal_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for LVGD.
|
||||
extern LVGD_TypeDef *sl_device_peripheral_lvgd_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for MAILBOX.
|
||||
extern MAILBOX_TypeDef *sl_device_peripheral_mailbox_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for MPAHBRAM.
|
||||
extern MPAHBRAM_TypeDef *sl_device_peripheral_mpahbram_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for MSC.
|
||||
extern MSC_TypeDef *sl_device_peripheral_msc_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for MVP.
|
||||
extern MVP_TypeDef *sl_device_peripheral_mvp_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for PCNT.
|
||||
extern PCNT_TypeDef *sl_device_peripheral_pcnt_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for PDM.
|
||||
extern PDM_TypeDef *sl_device_peripheral_pdm_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for PFMXPPRF.
|
||||
extern PFMXPPRF_TypeDef *sl_device_peripheral_pfmxpprf_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for PIXELRZ.
|
||||
extern PIXELRZ_TypeDef *sl_device_peripheral_pixelrz_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for PRS.
|
||||
extern PRS_TypeDef *sl_device_peripheral_prs_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for RFFPLL.
|
||||
extern RFFPLL_TypeDef *sl_device_peripheral_rffpll_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for RPA.
|
||||
extern RPA_TypeDef *sl_device_peripheral_rpa_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for RTCC.
|
||||
extern RTCC_TypeDef *sl_device_peripheral_rtcc_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for SCRATCHPAD.
|
||||
extern SCRATCHPAD_TypeDef *sl_device_peripheral_scratchpad_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for SEMAILBOX_AHBHOST.
|
||||
extern SEMAILBOX_AHBHOST_TypeDef *sl_device_peripheral_semailbox_ahbhost_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for SEMAILBOX_HOST.
|
||||
extern SEMAILBOX_HOST_TypeDef *sl_device_peripheral_semailbox_host_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for SEMAPHORE.
|
||||
extern SEMAPHORE_TypeDef *sl_device_peripheral_semaphore_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for SEPORTAL.
|
||||
extern SEPORTAL_TypeDef *sl_device_peripheral_seportal_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for SEPUF_APBCFG.
|
||||
extern SEPUF_APBCFG_TypeDef *sl_device_peripheral_sepuf_apbcfg_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for SMU.
|
||||
extern SMU_TypeDef *sl_device_peripheral_smu_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for SOCPLL.
|
||||
extern SOCPLL_TypeDef *sl_device_peripheral_socpll_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for SYMCRYPTO.
|
||||
extern SYMCRYPTO_TypeDef *sl_device_peripheral_symcrypto_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for SYSCFG.
|
||||
extern SYSCFG_TypeDef *sl_device_peripheral_syscfg_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for SYSCFG_CFGNS.
|
||||
extern SYSCFG_CFGNS_TypeDef *sl_device_peripheral_syscfg_cfgns_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for SYSRTC.
|
||||
extern SYSRTC_TypeDef *sl_device_peripheral_sysrtc_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for TIMER.
|
||||
extern TIMER_TypeDef *sl_device_peripheral_timer_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for ULFRCO.
|
||||
extern ULFRCO_TypeDef *sl_device_peripheral_ulfrco_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for USART.
|
||||
extern USART_TypeDef *sl_device_peripheral_usart_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for USBAHB_AHBS.
|
||||
extern USBAHB_AHBS_TypeDef *sl_device_peripheral_usbahb_ahbs_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for USBPLL.
|
||||
extern USBPLL_TypeDef *sl_device_peripheral_usbpll_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for USB_APBS.
|
||||
extern USB_APBS_TypeDef *sl_device_peripheral_usb_apbs_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for VDAC.
|
||||
extern VDAC_TypeDef *sl_device_peripheral_vdac_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External base address getter declaration for WDOG.
|
||||
extern WDOG_TypeDef *sl_device_peripheral_wdog_get_base_addr(const sl_peripheral_t peripheral);
|
||||
|
||||
// External clock branch getter declaration.
|
||||
extern sl_clock_branch_t sl_device_peripheral_get_clock_branch(const sl_peripheral_t peripheral);
|
||||
|
||||
// External bus clock getter declaration.
|
||||
extern sl_bus_clock_t sl_device_peripheral_get_bus_clock(const sl_peripheral_t peripheral);
|
||||
|
||||
#if defined(__ICCARM__)
|
||||
// Disable IAR multiple typedefs declaration warning.
|
||||
#pragma diag_default=Pe301
|
||||
#endif
|
||||
144
Libs/platform/service/hfxo_manager/inc/sl_hfxo_manager.h
Normal file
144
Libs/platform/service/hfxo_manager/inc/sl_hfxo_manager.h
Normal file
@@ -0,0 +1,144 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief HFXO Manager API definition.
|
||||
*******************************************************************************
|
||||
* # License
|
||||
* <b>Copyright 2019 Silicon Laboratories Inc. www.silabs.com</b>
|
||||
*******************************************************************************
|
||||
*
|
||||
* SPDX-License-Identifier: Zlib
|
||||
*
|
||||
* The licensor of this software is Silicon Laboratories Inc.
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/***************************************************************************//**
|
||||
* @addtogroup hfxo_manager HFXO Manager
|
||||
* @brief HFXO Manager
|
||||
* @details
|
||||
* ## Overview
|
||||
*
|
||||
* HFXO Manager is a platform service module intended to manage the High
|
||||
* Frequency Crystal Oscillator (HFXO) module and offer related functionalities
|
||||
* and services.
|
||||
* For the moment, this module is only supported on Silicon Labs series 2
|
||||
* devices.
|
||||
* Among others, it handles the HFXO startup failures. This is to support
|
||||
* sleepy crystals (crystals where the ESR value could change unexpectedly up
|
||||
* to 5 times its value during the startup). In case of a failure during the
|
||||
* HFXO startup, the HFXO Manager will retry the startup process with more
|
||||
* aggressive settings (sleepy crystal settings) to try waking up the crystal
|
||||
* from its sleepy state so that the ESR value can fall back to normal values.
|
||||
* Once the crystal is out of its sleepy state, the module will put back the
|
||||
* normal settings ensuring the right oscillation frequency. This feature can
|
||||
* be enabled/disabled via the configuration define
|
||||
* SL_HFXO_MANAGER_SLEEPY_CRYSTAL_SUPPORT.
|
||||
* The module catches startup failures through interrupts using the HFXO
|
||||
* interrupt handler. If your application also needs the HFXO interrupt
|
||||
* handler, the configuration define SL_HFXO_MANAGER_CUSTOM_HFXO_IRQ_HANDLER
|
||||
* can be used to remove the HFXO interrupt handler definition from the HFXO
|
||||
* Manager so that it can be defined in your application. In that case, your
|
||||
* definition of the HFXO Interrupt Handler will need to call the
|
||||
* sl_hfxo_manager_irq_handler() function so that HFXO Manager can continue
|
||||
* to work properly.
|
||||
* The HFXO Manager is also required by the Power Manager module for some
|
||||
* internal features and therefore becomes mandatory every time the Power
|
||||
* Manager is present.
|
||||
*
|
||||
*
|
||||
* ## Initialization
|
||||
*
|
||||
* Two functions are required to initialize the module.
|
||||
* sl_hfxo_manager_init_hardware() is to initialize the HFXO interrupts and
|
||||
* must therefore be called before any other HFXO initialization functions like
|
||||
* the emlib CMU_HFXOInit() or device_init function sl_device_init_hfxo().
|
||||
* The second initialization function sl_hfxo_manager_init() is required for
|
||||
* internal use and needs to be called before going to sleep.
|
||||
*
|
||||
* @{
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef SL_HFXO_MANAGER_H
|
||||
#define SL_HFXO_MANAGER_H
|
||||
|
||||
#include "sl_status.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/// @brief Sleepy Crystal settings
|
||||
typedef struct sl_hfxo_manager_sleepy_xtal_settings {
|
||||
uint32_t ana_ctune; ///< Tuning Capacitance values for XI and XO during startup intermediate and steady stages
|
||||
uint32_t core_bias_current; ///< Core Bias current value during all stages
|
||||
} sl_hfxo_manager_sleepy_xtal_settings_t;
|
||||
|
||||
/***************************************************************************//**
|
||||
* HFXO Manager module hardware specific initialization.
|
||||
******************************************************************************/
|
||||
void sl_hfxo_manager_init_hardware(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Initialize HFXO Manager module.
|
||||
*
|
||||
* @return Status Code.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_hfxo_manager_init(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Updates Sleepy Crystal settings.
|
||||
*
|
||||
* @param settings Pointer to settings structure
|
||||
*
|
||||
* @return Status Code.
|
||||
*
|
||||
* @note Those settings are temporarily used to force oscillation on sleepy
|
||||
* crystal.
|
||||
* Default values should be enough to wake-up sleepy crystals. Otherwise,
|
||||
* this function can be used.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_hfxo_manager_update_sleepy_xtal_settings(const sl_hfxo_manager_sleepy_xtal_settings_t *settings);
|
||||
|
||||
/***************************************************************************//**
|
||||
* When this callback function is called, it means that HFXO failed twice in
|
||||
* a row to start with normal configurations. This may mean that there is a
|
||||
* bad crystal. When getting this callback, HFXO is running but its properties
|
||||
* (frequency, precision) are not guaranteed. This should be considered as an
|
||||
* error situation.
|
||||
******************************************************************************/
|
||||
void sl_hfxo_manager_notify_consecutive_failed_startups(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* HFXO Manager HFXO interrupt handler.
|
||||
*
|
||||
* @note This function must be called by the HFXO interrupt handler in order
|
||||
* to support the HFXO Manager module.
|
||||
* This function handles the HFXO_IF_RDY, HFXO_IF_DNSERR and
|
||||
* HFXO_XTALCTRL_SKIPCOREBIASOPT interrupt flags.
|
||||
******************************************************************************/
|
||||
void sl_hfxo_manager_irq_handler(void);
|
||||
|
||||
/** @} (end addtogroup hfxo_manager) */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // SL_HFXO_MANAGER_H
|
||||
102
Libs/platform/service/hfxo_manager/inc/sli_hfxo_manager.h
Normal file
102
Libs/platform/service/hfxo_manager/inc/sli_hfxo_manager.h
Normal file
@@ -0,0 +1,102 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief HFXO Manager API definition.
|
||||
*******************************************************************************
|
||||
* # License
|
||||
* <b>Copyright 2019 Silicon Laboratories Inc. www.silabs.com</b>
|
||||
*******************************************************************************
|
||||
*
|
||||
* SPDX-License-Identifier: Zlib
|
||||
*
|
||||
* The licensor of this software is Silicon Laboratories Inc.
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef SLI_HFXO_MANAGER_H
|
||||
#define SLI_HFXO_MANAGER_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#if defined(SL_COMPONENT_CATALOG_PRESENT)
|
||||
#include "sl_component_catalog.h"
|
||||
#endif
|
||||
|
||||
#if defined(SL_CATALOG_SLEEPTIMER_PRESENT) && defined(SYSRTC_PRESENT)
|
||||
#include "sli_sleeptimer.h"
|
||||
#if (SL_SLEEPTIMER_PERIPHERAL == SL_SLEEPTIMER_PERIPHERAL_SYSRTC)
|
||||
#define HFXO_MANAGER_SLEEPTIMER_SYSRTC_INTEGRATION_ON
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/***************************************************************************//**
|
||||
* HFXO Manager module hardware specific initialization.
|
||||
******************************************************************************/
|
||||
void sli_hfxo_manager_init_hardware(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Function to call just before starting HFXO, to save current tick count.
|
||||
******************************************************************************/
|
||||
void sli_hfxo_manager_begin_startup_measurement(void);
|
||||
|
||||
#if defined(HFXO_MANAGER_SLEEPTIMER_SYSRTC_INTEGRATION_ON)
|
||||
/***************************************************************************//**
|
||||
* Function to call when a SYSRTC compare match event produces a PRS signal to
|
||||
start HFXO.
|
||||
******************************************************************************/
|
||||
void sli_hfxo_manager_retrieve_begining_startup_measurement(void);
|
||||
#endif
|
||||
|
||||
/***************************************************************************//**
|
||||
* Function to call just after HFXO becomes ready, to save current tick count
|
||||
* and calculate HFXO startup time.
|
||||
******************************************************************************/
|
||||
void sli_hfxo_manager_end_startup_measurement(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Retrieves HFXO startup time average value.
|
||||
******************************************************************************/
|
||||
uint32_t sli_hfxo_manager_get_startup_time(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Retrieves HFXO startup time latest value.
|
||||
******************************************************************************/
|
||||
uint32_t sli_hfxo_manager_get_latest_startup_time(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Checks if HFXO is ready and, if needed, waits for it to be.
|
||||
*
|
||||
* @param wait True, to wait for HFXO to be ready.
|
||||
* False, otherwise.
|
||||
*
|
||||
* @return True, if HFXO is ready.
|
||||
* False, otherwise.
|
||||
*
|
||||
* @note This will also make sure we are not in the process of restarting HFXO
|
||||
* with different settings.
|
||||
******************************************************************************/
|
||||
bool sli_hfxo_manager_is_hfxo_ready(bool wait);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SLI_HFXO_MANAGER_H */
|
||||
235
Libs/platform/service/hfxo_manager/src/sl_hfxo_manager.c
Normal file
235
Libs/platform/service/hfxo_manager/src/sl_hfxo_manager.c
Normal file
@@ -0,0 +1,235 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief HFXO Manager API implementation.
|
||||
*******************************************************************************
|
||||
* # License
|
||||
* <b>Copyright 2019 Silicon Laboratories Inc. www.silabs.com</b>
|
||||
*******************************************************************************
|
||||
*
|
||||
* SPDX-License-Identifier: Zlib
|
||||
*
|
||||
* The licensor of this software is Silicon Laboratories Inc.
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include "em_device.h"
|
||||
#include "sl_hfxo_manager.h"
|
||||
#include "sli_hfxo_manager.h"
|
||||
#include "sli_hfxo_manager_internal.h"
|
||||
#include "sl_sleeptimer.h"
|
||||
#include "sl_assert.h"
|
||||
#include "sl_status.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
/*******************************************************************************
|
||||
********************************* DEFINES *********************************
|
||||
******************************************************************************/
|
||||
// Table size of HFXO wake-up time measurement
|
||||
#define HFXO_STARTUP_TIME_TABLE_SIZE 10
|
||||
|
||||
// Default time value in microseconds required to wake-up the hfxo oscillator.
|
||||
#define HFXO_STARTUP_TIME_DEFAULT_VALUE_US (600u)
|
||||
|
||||
/*******************************************************************************
|
||||
***************************** DATA TYPES **********************************
|
||||
******************************************************************************/
|
||||
|
||||
/*******************************************************************************
|
||||
*************************** LOCAL VARIABLES ********************************
|
||||
******************************************************************************/
|
||||
|
||||
// Time in ticks required for HFXO start-up after wake-up from sleep.
|
||||
static volatile uint32_t hfxo_startup_time_tick = 0;
|
||||
|
||||
static volatile uint32_t hfxo_last_startup_time = 0;
|
||||
|
||||
static uint32_t hfxo_startup_time_table[HFXO_STARTUP_TIME_TABLE_SIZE];
|
||||
|
||||
static uint8_t hfxo_startup_time_table_index = 0;
|
||||
|
||||
static uint32_t hfxo_startup_time_sum_average = 0;
|
||||
|
||||
static volatile uint32_t hfxo_startup_time_tc_initial = 0;
|
||||
|
||||
static volatile bool hfxo_measurement_on = false;
|
||||
|
||||
/*******************************************************************************
|
||||
************************** GLOBAL FUNCTIONS *******************************
|
||||
******************************************************************************/
|
||||
|
||||
/***************************************************************************//**
|
||||
* HFXO Manager module hardware specific initialization.
|
||||
******************************************************************************/
|
||||
void sl_hfxo_manager_init_hardware(void)
|
||||
{
|
||||
sli_hfxo_manager_init_hardware();
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Initialize HFXO Manager module.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_hfxo_manager_init(void)
|
||||
{
|
||||
sl_status_t status;
|
||||
|
||||
// Initialize Sleeptimer module in case not already done.
|
||||
status = sl_sleeptimer_init();
|
||||
if (status != SL_STATUS_OK) {
|
||||
return status;
|
||||
}
|
||||
#if defined(HFXO_MANAGER_SLEEPTIMER_SYSRTC_INTEGRATION_ON)
|
||||
// Additional Sleeptimer HW configuration if SYSRTC is used
|
||||
sli_sleeptimer_hal_hfxo_manager_integration_init();
|
||||
#endif
|
||||
|
||||
// Set HFXO startup time to conservative default value
|
||||
hfxo_startup_time_tick = (((HFXO_STARTUP_TIME_DEFAULT_VALUE_US * sl_sleeptimer_get_timer_frequency()) + (1000000 - 1)) / 1000000);
|
||||
for (uint8_t i = 0; i < HFXO_STARTUP_TIME_TABLE_SIZE; i++) {
|
||||
hfxo_startup_time_table[i] = hfxo_startup_time_tick;
|
||||
hfxo_startup_time_sum_average += hfxo_startup_time_tick;
|
||||
}
|
||||
|
||||
return SL_STATUS_OK;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Updates Sleepy Crystal settings.
|
||||
*
|
||||
* @param settings Pointer to settings structure
|
||||
*
|
||||
* @return Status Code.
|
||||
*
|
||||
* @note Those settings are temporarily used to force oscillation on sleepy
|
||||
* crystal.
|
||||
* Default values should be enough to wake-up sleepy crystals. Otherwise,
|
||||
* this function can be used.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_hfxo_manager_update_sleepy_xtal_settings(const sl_hfxo_manager_sleepy_xtal_settings_t *settings)
|
||||
{
|
||||
return sli_hfxo_manager_update_sleepy_xtal_settings_hardware(settings);
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* When this callback function is called, it means that HFXO failed twice in
|
||||
* a row to start with normal configurations. This may mean that there is a
|
||||
* bad crystal. When getting this callback, HFXO is running but its properties
|
||||
* (frequency, precision) are not guaranteed. This should be considered as an
|
||||
* error situation.
|
||||
******************************************************************************/
|
||||
__WEAK void sl_hfxo_manager_notify_consecutive_failed_startups(void)
|
||||
{
|
||||
EFM_ASSERT(false);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
********************** GLOBAL INTERNAL FUNCTIONS **************************
|
||||
******************************************************************************/
|
||||
|
||||
/***************************************************************************//**
|
||||
* Function to call just before starting HFXO, to save current tick count.
|
||||
******************************************************************************/
|
||||
void sli_hfxo_manager_begin_startup_measurement(void)
|
||||
{
|
||||
hfxo_measurement_on = true;
|
||||
hfxo_startup_time_tc_initial = sl_sleeptimer_get_tick_count();
|
||||
}
|
||||
|
||||
#if defined(HFXO_MANAGER_SLEEPTIMER_SYSRTC_INTEGRATION_ON)
|
||||
/***************************************************************************//**
|
||||
* Function to retrieve the capture channel value that was saved when
|
||||
* HFXO became enabled.
|
||||
*
|
||||
* @note SYSRTC Capture channel is used to save when HFXO becomes enabled.
|
||||
* The HFXO startup measurement will only be done based on the capture
|
||||
* channel if the capture value is valid.
|
||||
******************************************************************************/
|
||||
void sli_hfxo_manager_retrieve_begining_startup_measurement(void)
|
||||
{
|
||||
// ULFRCO does not have the precision to measure the HFXO startup time.
|
||||
// So just return if ULFRCO is used as source oscillator.
|
||||
if (sl_sleeptimer_get_timer_frequency() <= SystemULFRCOClockGet()) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t startup_time = sli_sleeptimer_get_capture();
|
||||
|
||||
if (startup_time != 0) {
|
||||
hfxo_startup_time_tc_initial = startup_time;
|
||||
hfxo_measurement_on = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/***************************************************************************//**
|
||||
* Function to call just after HFXO becomes ready, to save current tick count
|
||||
* and calculate HFXO startup time.
|
||||
******************************************************************************/
|
||||
void sli_hfxo_manager_end_startup_measurement(void)
|
||||
{
|
||||
uint32_t default_startup_ticks;
|
||||
|
||||
if (hfxo_measurement_on == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
hfxo_last_startup_time = sl_sleeptimer_get_tick_count() - hfxo_startup_time_tc_initial;
|
||||
|
||||
// With low precision clock, the HFXO startup time measure could be zero.
|
||||
// In that case, ensure it's a least 1 tick.
|
||||
hfxo_last_startup_time = (hfxo_last_startup_time == 0) ? 1 : hfxo_last_startup_time;
|
||||
|
||||
// Skip measurement if value is out of bound
|
||||
default_startup_ticks = (((HFXO_STARTUP_TIME_DEFAULT_VALUE_US * sl_sleeptimer_get_timer_frequency()) + (1000000 - 1)) / 1000000);
|
||||
EFM_ASSERT(hfxo_last_startup_time <= default_startup_ticks);
|
||||
if (hfxo_last_startup_time > default_startup_ticks) {
|
||||
hfxo_measurement_on = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate average for HFXO restore time
|
||||
hfxo_startup_time_sum_average -= (int32_t)hfxo_startup_time_table[hfxo_startup_time_table_index] - (int32_t)hfxo_last_startup_time;
|
||||
hfxo_startup_time_table[hfxo_startup_time_table_index] = hfxo_last_startup_time;
|
||||
hfxo_startup_time_tick = ((hfxo_startup_time_sum_average + (HFXO_STARTUP_TIME_TABLE_SIZE - 1) ) / HFXO_STARTUP_TIME_TABLE_SIZE);
|
||||
|
||||
// Update index of wakeup time table
|
||||
hfxo_startup_time_table_index++;
|
||||
hfxo_startup_time_table_index %= HFXO_STARTUP_TIME_TABLE_SIZE;
|
||||
|
||||
hfxo_measurement_on = false;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Retrieves HFXO startup time average value.
|
||||
*
|
||||
* @return HFXO startup time average value.
|
||||
******************************************************************************/
|
||||
uint32_t sli_hfxo_manager_get_startup_time(void)
|
||||
{
|
||||
return hfxo_startup_time_tick;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Retrieves HFXO startup time latest value.
|
||||
*
|
||||
* @return HFXO startup time latest value.
|
||||
******************************************************************************/
|
||||
uint32_t sli_hfxo_manager_get_latest_startup_time(void)
|
||||
{
|
||||
return hfxo_last_startup_time;
|
||||
}
|
||||
410
Libs/platform/service/hfxo_manager/src/sl_hfxo_manager_hal_s2.c
Normal file
410
Libs/platform/service/hfxo_manager/src/sl_hfxo_manager_hal_s2.c
Normal file
@@ -0,0 +1,410 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief HFXO Manager HAL series 2 Devices.
|
||||
*******************************************************************************
|
||||
* # License
|
||||
* <b>Copyright 2019 Silicon Laboratories Inc. www.silabs.com</b>
|
||||
*******************************************************************************
|
||||
*
|
||||
* SPDX-License-Identifier: Zlib
|
||||
*
|
||||
* The licensor of this software is Silicon Laboratories Inc.
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
******************************************************************************/
|
||||
#include "em_device.h"
|
||||
#if defined(_SILICON_LABS_32B_SERIES_2)
|
||||
#include "sl_assert.h"
|
||||
#include "sl_core.h"
|
||||
#include "sli_hfxo_manager.h"
|
||||
#include "sl_hfxo_manager.h"
|
||||
#include "sl_hfxo_manager_config.h"
|
||||
#include "sl_status.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
/*******************************************************************************
|
||||
********************************* DEFINES *********************************
|
||||
******************************************************************************/
|
||||
|
||||
#if (defined(SL_HFXO_MANAGER_SLEEPY_CRYSTAL_SUPPORT) \
|
||||
&& (SL_HFXO_MANAGER_SLEEPY_CRYSTAL_SUPPORT == 1) \
|
||||
&& defined(SL_CATALOG_POWER_MANAGER_DEEPSLEEP_BLOCKING_HFXO_RESTORE_PRESENT))
|
||||
#error Component power_manager_deepsleep_blocking_hfxo_restore is not compatible with SL_HFXO_MANAGER_SLEEPY_CRYSTAL_SUPPORT configuration
|
||||
#endif
|
||||
|
||||
// Defines for hidden field FORCERAWCLK in HFXO_CTRL register
|
||||
#define _HFXO_MANAGER_CTRL_FORCERAWCLK_SHIFT 31
|
||||
#define _HFXO_MANAGER_CTRL_FORCERAWCLK_MASK 0x80000000UL
|
||||
#define HFXO_MANAGER_CTRL_FORCERAWCLK (0x1UL << _HFXO_MANAGER_CTRL_FORCERAWCLK_SHIFT)
|
||||
|
||||
// Defines for hidden PKDETCTRL register
|
||||
#define HFXO_MANAGER_PKDETCTRL (*((volatile uint32_t *)(HFXO0_BASE + 0x34UL)))
|
||||
#define _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT 8
|
||||
#define _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_MASK 0xF00UL
|
||||
#define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V105MV (0x00000000UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
|
||||
#define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V132MV (0x00000001UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
|
||||
#define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V157MV (0x00000002UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
|
||||
#define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V184MV (0x00000003UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
|
||||
#define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V210MV (0x00000004UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
|
||||
#define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V236MV (0x00000005UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
|
||||
#define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V262MV (0x00000006UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
|
||||
#define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V289MV (0x00000007UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
|
||||
#define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V315MV (0x00000008UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
|
||||
#define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V341MV (0x00000009UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
|
||||
#define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V367MV (0x0000000AUL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
|
||||
#define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V394MV (0x0000000BUL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
|
||||
#define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V420MV (0x0000000CUL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
|
||||
#define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V446MV (0x0000000DUL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
|
||||
#define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V472MV (0x0000000EUL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
|
||||
#define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V499MV (0x0000000FUL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
|
||||
|
||||
// IRQ Name depending on devices
|
||||
#if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1)
|
||||
#define HFXO_IRQ_NUMBER HFXO00_IRQn
|
||||
#define HFXO_IRQ_HANDLER_FUNCTION HFXO00_IRQHandler
|
||||
#else
|
||||
#define HFXO_IRQ_NUMBER HFXO0_IRQn
|
||||
#define HFXO_IRQ_HANDLER_FUNCTION HFXO0_IRQHandler
|
||||
#endif
|
||||
|
||||
// Default values for the Sleepy Crystal settings
|
||||
// Should be enough to guaranty HFXO startup
|
||||
#define SLEEPY_XTAL_SETTING_DEFAULT_PKDETTHSTARTUPI HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V157MV
|
||||
#define SLEEPY_XTAL_SETTING_DEFAULT_CTUNEANA 100u
|
||||
#define SLEEPY_XTAL_SETTING_DEFAULT_COREBIAS 255u
|
||||
|
||||
/*******************************************************************************
|
||||
*************************** LOCAL VARIABLES ********************************
|
||||
******************************************************************************/
|
||||
|
||||
// Error flag to indicate if we failed the startup process
|
||||
static volatile bool error_flag = false;
|
||||
|
||||
#if (SL_HFXO_MANAGER_SLEEPY_CRYSTAL_SUPPORT == 1)
|
||||
// Error retry counter
|
||||
static volatile uint8_t error_try_cnt = 0;
|
||||
|
||||
// Error State status
|
||||
static volatile bool in_error_state = false;
|
||||
|
||||
// Variables to save normal settings
|
||||
static uint32_t pkdettusstartupi_saved;
|
||||
static uint32_t ctunexiana_saved;
|
||||
static uint32_t ctunexoana_saved;
|
||||
static uint32_t corebiasana_saved;
|
||||
static uint32_t corebiasstartup_saved;
|
||||
static uint32_t corebiasstartupi_saved;
|
||||
|
||||
// Variables for Sleepy Crystal settings
|
||||
static uint32_t sleepy_xtal_settings_pkdettusstartupi = SLEEPY_XTAL_SETTING_DEFAULT_PKDETTHSTARTUPI; // Value already shifted
|
||||
static uint32_t sleepy_xtal_settings_ctuneana = SLEEPY_XTAL_SETTING_DEFAULT_CTUNEANA;
|
||||
static uint32_t sleepy_xtal_settings_corebias = SLEEPY_XTAL_SETTING_DEFAULT_COREBIAS;
|
||||
#endif
|
||||
|
||||
/***************************************************************************//**
|
||||
* HFXO ready notification callback for internal use with power manager
|
||||
******************************************************************************/
|
||||
__WEAK void sli_hfxo_manager_notify_ready_for_power_manager(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* HFXO PRS ready notification callback for internal use with power manager
|
||||
******************************************************************************/
|
||||
__WEAK void sli_hfxo_notify_ready_for_power_manager_from_prs(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Hardware specific initialization.
|
||||
******************************************************************************/
|
||||
void sli_hfxo_manager_init_hardware(void)
|
||||
{
|
||||
// Increase HFXO Interrupt priority so that it won't be masked by BASEPRI
|
||||
// and will preempt other interrupts.
|
||||
NVIC_SetPriority(HFXO_IRQ_NUMBER, CORE_ATOMIC_BASE_PRIORITY_LEVEL - 1);
|
||||
|
||||
// Enable HFXO Interrupt if HFXO is used
|
||||
#if _SILICON_LABS_32B_SERIES_2_CONFIG >= 2
|
||||
CMU->CLKEN0_SET = CMU_CLKEN0_HFXO0;
|
||||
#endif
|
||||
|
||||
HFXO0->IEN_CLR = HFXO_IEN_RDY | HFXO_IEN_DNSERR | HFXO_IEN_COREBIASOPTERR;
|
||||
#if defined(HFXO_MANAGER_SLEEPTIMER_SYSRTC_INTEGRATION_ON)
|
||||
HFXO0->IEN_CLR = HFXO_IEN_PRSRDY;
|
||||
#endif
|
||||
|
||||
HFXO0->IF_CLR = HFXO_IF_RDY | HFXO_IF_DNSERR | HFXO_IEN_COREBIASOPTERR;
|
||||
#if defined(HFXO_MANAGER_SLEEPTIMER_SYSRTC_INTEGRATION_ON)
|
||||
HFXO0->IF_CLR = HFXO_IF_PRSRDY;
|
||||
#endif
|
||||
|
||||
NVIC_ClearPendingIRQ(HFXO_IRQ_NUMBER);
|
||||
NVIC_EnableIRQ(HFXO_IRQ_NUMBER);
|
||||
|
||||
HFXO0->IEN_SET = HFXO_IEN_RDY | HFXO_IEN_DNSERR | HFXO_IEN_COREBIASOPTERR;
|
||||
|
||||
#if defined(HFXO_MANAGER_SLEEPTIMER_SYSRTC_INTEGRATION_ON)
|
||||
HFXO0->IEN_SET = HFXO_IEN_PRSRDY;
|
||||
HFXO0->CTRL &= ~(_HFXO_CTRL_DISONDEMANDPRS_MASK & HFXO_CTRL_DISONDEMANDPRS_DEFAULT);
|
||||
HFXO0->CTRL |= HFXO_CTRL_PRSSTATUSSEL1_ENS;
|
||||
#endif
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Updates sleepy crystal settings in specific hardware registers.
|
||||
******************************************************************************/
|
||||
sl_status_t sli_hfxo_manager_update_sleepy_xtal_settings_hardware(const sl_hfxo_manager_sleepy_xtal_settings_t *settings)
|
||||
{
|
||||
#if (SL_HFXO_MANAGER_SLEEPY_CRYSTAL_SUPPORT == 1)
|
||||
EFM_ASSERT(settings->ana_ctune <= (_HFXO_XTALCTRL_CTUNEXIANA_MASK >> _HFXO_XTALCTRL_CTUNEXIANA_SHIFT));
|
||||
EFM_ASSERT(settings->core_bias_current <= (_HFXO_XTALCTRL_COREBIASANA_MASK >> _HFXO_XTALCTRL_COREBIASANA_SHIFT));
|
||||
|
||||
sleepy_xtal_settings_ctuneana = settings->ana_ctune;
|
||||
sleepy_xtal_settings_corebias = settings->core_bias_current;
|
||||
|
||||
return SL_STATUS_OK;
|
||||
#else
|
||||
(void)settings;
|
||||
return SL_STATUS_NOT_AVAILABLE;
|
||||
#endif
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Checks if HFXO is ready and, if needed, waits for it to be.
|
||||
*
|
||||
* @note This will also make sure we are not in the process of restarting HFXO
|
||||
* with different settings.
|
||||
******************************************************************************/
|
||||
bool sli_hfxo_manager_is_hfxo_ready(bool wait)
|
||||
{
|
||||
bool ready = false;
|
||||
|
||||
do {
|
||||
#if defined(HFXO_MANAGER_SLEEPTIMER_SYSRTC_INTEGRATION_ON)
|
||||
ready = (((HFXO0->STATUS & (HFXO_STATUS_RDY | HFXO_STATUS_PRSRDY)) != 0) && !error_flag) ? true : false;
|
||||
#else
|
||||
ready = (((HFXO0->STATUS & HFXO_STATUS_RDY) != 0) && !error_flag) ? true : false;
|
||||
#endif
|
||||
} while (!ready && wait);
|
||||
|
||||
return ready;
|
||||
}
|
||||
|
||||
#if (SL_HFXO_MANAGER_CUSTOM_HFXO_IRQ_HANDLER == 0)
|
||||
/*******************************************************************************
|
||||
* HFXO interrupt handler.
|
||||
*
|
||||
* @note The HFXOx_IRQHandler provided by HFXO Manager will call
|
||||
* @ref sl_hfxo_manager_irq_handler. Configure SL_HFXO_MANAGER_CUSTOM_HFXO_IRQ_HANDLER
|
||||
* if the application wants to implement its own HFXOx_IRQHandler.
|
||||
******************************************************************************/
|
||||
void HFXO_IRQ_HANDLER_FUNCTION(void)
|
||||
{
|
||||
sl_hfxo_manager_irq_handler();
|
||||
}
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
* HFXO Manager HFXO interrupt handler.
|
||||
******************************************************************************/
|
||||
void sl_hfxo_manager_irq_handler(void)
|
||||
{
|
||||
uint32_t irq_flag = HFXO0->IF;
|
||||
#if (SL_HFXO_MANAGER_SLEEPY_CRYSTAL_SUPPORT == 1)
|
||||
bool disondemand = (HFXO0->CTRL & _HFXO_CTRL_DISONDEMAND_MASK) ? true : false;
|
||||
bool forceen = (HFXO0->CTRL & _HFXO_CTRL_FORCEEN_MASK) ? true : false;
|
||||
#endif
|
||||
|
||||
#if defined(HFXO_MANAGER_SLEEPTIMER_SYSRTC_INTEGRATION_ON)
|
||||
if (irq_flag & HFXO_IF_PRSRDY) {
|
||||
// Clear PRS RDY flag and EM23ONDEMAND
|
||||
HFXO0->IF_CLR = irq_flag & HFXO_IF_PRSRDY;
|
||||
HFXO0->CTRL_CLR = HFXO_CTRL_EM23ONDEMAND;
|
||||
|
||||
// Only retrieve start of measurement if HFXO is not already ready.
|
||||
if ((HFXO0->STATUS & HFXO_STATUS_RDY) == 0) {
|
||||
sli_hfxo_manager_retrieve_begining_startup_measurement();
|
||||
}
|
||||
|
||||
// Notify power manager HFXO is ready
|
||||
sli_hfxo_notify_ready_for_power_manager_from_prs();
|
||||
sli_hfxo_manager_notify_ready_for_power_manager();
|
||||
|
||||
// Update sleep on isr exit flag
|
||||
sli_sleeptimer_update_sleep_on_isr_exit(true);
|
||||
|
||||
// Reset PRS signal through Sleeptimer
|
||||
sli_sleeptimer_reset_prs_signal();
|
||||
}
|
||||
#endif
|
||||
|
||||
// RDY Interrupt Flag Handling
|
||||
if (irq_flag & HFXO_IF_RDY) {
|
||||
// Clear Ready flag
|
||||
HFXO0->IF_CLR = irq_flag & HFXO_IF_RDY;
|
||||
|
||||
#if (SL_HFXO_MANAGER_SLEEPY_CRYSTAL_SUPPORT == 1)
|
||||
if (error_flag) {
|
||||
// Clear error flag, i.e. we successfully stated HFXO with the modified settings
|
||||
error_flag = false;
|
||||
|
||||
// If it's the first time we succeed after an error, try back the normal settings
|
||||
if (error_try_cnt <= 1) {
|
||||
// Disable HFXO.
|
||||
HFXO0->CTRL_CLR = HFXO_CTRL_FORCEEN;
|
||||
HFXO0->CTRL_SET = HFXO_CTRL_DISONDEMAND;
|
||||
|
||||
while ((HFXO0->STATUS & HFXO_STATUS_ENS) != 0) {
|
||||
}
|
||||
|
||||
// Put back normal settings
|
||||
HFXO_MANAGER_PKDETCTRL = (HFXO_MANAGER_PKDETCTRL & ~_HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_MASK) | pkdettusstartupi_saved;
|
||||
HFXO0->XTALCTRL = (HFXO0->XTALCTRL & ~(_HFXO_XTALCTRL_CTUNEXIANA_MASK | _HFXO_XTALCTRL_CTUNEXOANA_MASK))
|
||||
| ctunexiana_saved
|
||||
| ctunexoana_saved;
|
||||
HFXO0->XTALCFG = (HFXO0->XTALCFG & ~(_HFXO_XTALCFG_COREBIASSTARTUPI_MASK | _HFXO_XTALCFG_COREBIASSTARTUP_MASK))
|
||||
| corebiasstartup_saved
|
||||
| corebiasstartupi_saved;
|
||||
HFXO0->XTALCTRL = (HFXO0->XTALCTRL & ~_HFXO_XTALCTRL_COREBIASANA_MASK) | corebiasana_saved;
|
||||
|
||||
// Put back FORCEEN and DISONDEMAND state
|
||||
if (!disondemand) {
|
||||
HFXO0->CTRL_CLR = HFXO_CTRL_DISONDEMAND;
|
||||
} else {
|
||||
HFXO0->CTRL_SET = HFXO_CTRL_DISONDEMAND;
|
||||
}
|
||||
if (forceen) {
|
||||
HFXO0->CTRL_SET = HFXO_CTRL_FORCEEN;
|
||||
} else {
|
||||
HFXO0->CTRL_CLR = HFXO_CTRL_FORCEEN;
|
||||
}
|
||||
} else {
|
||||
// Call notification function to tell users that sleepy crystal settings are kept
|
||||
// This should only happen if you are in test condition or if you have a bad crystal.
|
||||
sl_hfxo_manager_notify_consecutive_failed_startups();
|
||||
in_error_state = true;
|
||||
}
|
||||
} else {
|
||||
sli_hfxo_manager_end_startup_measurement();
|
||||
|
||||
sli_hfxo_manager_notify_ready_for_power_manager();
|
||||
|
||||
// Clear counter since we successfully started HFXO with normal settings
|
||||
// or we are just keeping sleepy crystal settings indefinitely.
|
||||
error_try_cnt = 0;
|
||||
}
|
||||
#else
|
||||
sli_hfxo_manager_end_startup_measurement();
|
||||
|
||||
sli_hfxo_manager_notify_ready_for_power_manager();
|
||||
#endif
|
||||
}
|
||||
|
||||
// DNSERR Interrupt Flag Handling
|
||||
if (irq_flag & HFXO_IF_DNSERR) {
|
||||
// Clear error flag
|
||||
HFXO0->IF_CLR = irq_flag & HFXO_IF_DNSERR;
|
||||
|
||||
#if (SL_HFXO_MANAGER_SLEEPY_CRYSTAL_SUPPORT == 1)
|
||||
// We should not fail twice in a row
|
||||
EFM_ASSERT(error_flag == false);
|
||||
|
||||
// Update global variables related to error.
|
||||
error_flag = true;
|
||||
error_try_cnt++;
|
||||
|
||||
// Save current settings
|
||||
pkdettusstartupi_saved = (HFXO_MANAGER_PKDETCTRL & _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_MASK);
|
||||
ctunexiana_saved = (HFXO0->XTALCTRL & _HFXO_XTALCTRL_CTUNEXIANA_MASK);
|
||||
ctunexoana_saved = (HFXO0->XTALCTRL & _HFXO_XTALCTRL_CTUNEXOANA_MASK);
|
||||
corebiasana_saved = (HFXO0->XTALCTRL & _HFXO_XTALCTRL_COREBIASANA_MASK);
|
||||
corebiasstartup_saved = (HFXO0->XTALCFG & _HFXO_XTALCFG_COREBIASSTARTUP_MASK);
|
||||
corebiasstartupi_saved = (HFXO0->XTALCFG & _HFXO_XTALCFG_COREBIASSTARTUPI_MASK);
|
||||
|
||||
// Disable HFXO.
|
||||
HFXO0->CTRL_CLR = HFXO_CTRL_FORCEEN;
|
||||
HFXO0->CTRL_SET = HFXO_CTRL_DISONDEMAND;
|
||||
|
||||
// Use FORCERAWCLK bit to exit error state when disabling
|
||||
HFXO0->CTRL_SET = HFXO_MANAGER_CTRL_FORCERAWCLK;
|
||||
while ((HFXO0->STATUS & _HFXO_STATUS_ENS_MASK) != 0U) {
|
||||
}
|
||||
HFXO0->CTRL_CLR = HFXO_MANAGER_CTRL_FORCERAWCLK;
|
||||
|
||||
// Change settings:
|
||||
//Reduce Peak Detection Threshold for Startup Intermediate stage to 2 (V157MV)
|
||||
HFXO_MANAGER_PKDETCTRL = (HFXO_MANAGER_PKDETCTRL & ~_HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_MASK) | sleepy_xtal_settings_pkdettusstartupi;
|
||||
// Reduce CTUNE values for steady stage
|
||||
if (((ctunexiana_saved >> _HFXO_XTALCTRL_CTUNEXIANA_SHIFT) > 100)
|
||||
|| ((ctunexoana_saved >> _HFXO_XTALCTRL_CTUNEXOANA_SHIFT) > 100)) {
|
||||
HFXO0->XTALCTRL = (HFXO0->XTALCTRL & ~(_HFXO_XTALCTRL_CTUNEXIANA_MASK | _HFXO_XTALCTRL_CTUNEXOANA_MASK))
|
||||
| (sleepy_xtal_settings_ctuneana << _HFXO_XTALCTRL_CTUNEXIANA_SHIFT)
|
||||
| (sleepy_xtal_settings_ctuneana << _HFXO_XTALCTRL_CTUNEXOANA_SHIFT);
|
||||
}
|
||||
// Increase core bias current at all stages
|
||||
HFXO0->XTALCFG = (HFXO0->XTALCFG & ~(_HFXO_XTALCFG_COREBIASSTARTUPI_MASK | _HFXO_XTALCFG_COREBIASSTARTUP_MASK))
|
||||
| ((sleepy_xtal_settings_corebias >> 2) << _HFXO_XTALCFG_COREBIASSTARTUPI_SHIFT)
|
||||
| ((sleepy_xtal_settings_corebias >> 2) << _HFXO_XTALCFG_COREBIASSTARTUP_SHIFT);
|
||||
HFXO0->XTALCTRL = (HFXO0->XTALCTRL & ~_HFXO_XTALCTRL_COREBIASANA_MASK)
|
||||
| (sleepy_xtal_settings_corebias << _HFXO_XTALCTRL_COREBIASANA_SHIFT);
|
||||
|
||||
// Put back FORCEEN and DISONDEMAND state
|
||||
if (!disondemand) {
|
||||
HFXO0->CTRL_CLR = HFXO_CTRL_DISONDEMAND;
|
||||
} else {
|
||||
HFXO0->CTRL_SET = HFXO_CTRL_DISONDEMAND;
|
||||
}
|
||||
if (forceen) {
|
||||
HFXO0->CTRL_SET = HFXO_CTRL_FORCEEN;
|
||||
} else {
|
||||
HFXO0->CTRL_CLR = HFXO_CTRL_FORCEEN;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (irq_flag & HFXO_IF_COREBIASOPTERR) {
|
||||
// Clear Core Bias Optimization error flag
|
||||
HFXO0->IF_CLR = irq_flag & HFXO_IF_COREBIASOPTERR;
|
||||
|
||||
#if (SL_HFXO_MANAGER_SLEEPY_CRYSTAL_SUPPORT == 1)
|
||||
// In case the Core Bias Optimization fails during error handling,
|
||||
// we disable it
|
||||
if (in_error_state == true) {
|
||||
// Disable HFXO.
|
||||
HFXO0->CTRL_CLR = HFXO_CTRL_FORCEEN;
|
||||
HFXO0->CTRL_SET = HFXO_CTRL_DISONDEMAND;
|
||||
|
||||
while ((HFXO0->STATUS & HFXO_STATUS_ENS) != 0) {
|
||||
}
|
||||
|
||||
// Skip Core Bias Optimization in case of error
|
||||
HFXO0->XTALCTRL_SET = HFXO_XTALCTRL_SKIPCOREBIASOPT;
|
||||
|
||||
// Put back FORCEEN and DISONDEMAND state
|
||||
if (!disondemand) {
|
||||
HFXO0->CTRL_CLR = HFXO_CTRL_DISONDEMAND;
|
||||
} else {
|
||||
HFXO0->CTRL_SET = HFXO_CTRL_DISONDEMAND;
|
||||
}
|
||||
if (forceen) {
|
||||
HFXO0->CTRL_SET = HFXO_CTRL_FORCEEN;
|
||||
} else {
|
||||
HFXO0->CTRL_CLR = HFXO_CTRL_FORCEEN;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif // _SILICON_LABS_32B_SERIES_2
|
||||
@@ -0,0 +1,50 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief HFXO 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.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef SLI_HFXO_MANAGER_INTERNAL_H
|
||||
#define SLI_HFXO_MANAGER_INTERNAL_H
|
||||
|
||||
#include "sl_hfxo_manager.h"
|
||||
#include "sl_status.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/***************************************************************************//**
|
||||
* Updates sleepy crystal settings in specific hardware registers.
|
||||
******************************************************************************/
|
||||
sl_status_t sli_hfxo_manager_update_sleepy_xtal_settings_hardware(const sl_hfxo_manager_sleepy_xtal_settings_t *settings);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SLI_HFXO_MANAGER_INTERNAL_H */
|
||||
@@ -0,0 +1,59 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief CMSIS NVIC Virtual Header
|
||||
*******************************************************************************
|
||||
* # License
|
||||
* <b>Copyright 2023 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 CMSIS_NVIC_VIRTUAL_H
|
||||
#define CMSIS_NVIC_VIRTUAL_H
|
||||
|
||||
#include "sl_interrupt_manager.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// NVIC backward compatibility layer
|
||||
#define NVIC_EnableIRQ(irqn) sl_interrupt_manager_enable_irq(irqn)
|
||||
#define NVIC_DisableIRQ(irqn) sl_interrupt_manager_disable_irq(irqn)
|
||||
#define NVIC_SetPriority sl_interrupt_manager_set_irq_priority
|
||||
#define NVIC_GetPriority sl_interrupt_manager_get_irq_priority
|
||||
#define NVIC_SystemReset sl_interrupt_manager_reset_system
|
||||
#define NVIC_GetPendingIRQ(irqn) sl_interrupt_manager_is_irq_pending(irqn)
|
||||
#define NVIC_SetPendingIRQ(irqn) sl_interrupt_manager_set_irq_pending(irqn)
|
||||
#define NVIC_ClearPendingIRQ(irqn) sl_interrupt_manager_clear_irq_pending(irqn)
|
||||
#define NVIC_GetActive(irqn) sl_interrupt_manager_get_active_irq(irqn)
|
||||
|
||||
// Original NVIC calls
|
||||
#define NVIC_SetPriorityGrouping __NVIC_SetPriorityGrouping
|
||||
#define NVIC_GetPriorityGrouping __NVIC_GetPriorityGrouping
|
||||
#define NVIC_GetEnableIRQ __NVIC_GetEnableIRQ
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SL_CMSIS_NVIC_VIRTUAL_H */
|
||||
@@ -0,0 +1,404 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief Interrupt Management API to enable and configure interrupts.
|
||||
*******************************************************************************
|
||||
* # License
|
||||
* <b>Copyright 2023 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_INTERRUPT_MANAGER_H
|
||||
#define SL_INTERRUPT_MANAGER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "sl_core.h"
|
||||
#include "sl_status.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/***************************************************************************//**
|
||||
* @addtogroup interrupt_manager Interrupt Manager
|
||||
* @brief Interrupt management service can be used for general interrupt management.
|
||||
* The source files for Interrupt Manager platform software module are present under
|
||||
* platform/services/interrupt_manager.
|
||||
* @details
|
||||
* ## Overview
|
||||
* The Interrupt Manager is a service that offers interupt management functions and configurations
|
||||
* for setting the interrupt vector in RAM, managing the core reset initiation function and
|
||||
* doing general interrupt management operations.
|
||||
*
|
||||
* ## Configuration Options
|
||||
*
|
||||
* Some properties of the Interrupt Manager are compile-time configurable. These
|
||||
* properties are set in the sl_interrupt_manager_s2_config.h file.
|
||||
* These are the available configuration parameters with default values defined.
|
||||
* @code
|
||||
*
|
||||
* // <q SL_INTERRUPT_MANAGER_S2_INTERRUPTS_IN_RAM> Put the interrupt vector table in RAM.
|
||||
* // <i> Set to 1 to put the vector table in RAM.
|
||||
* // <i> Default: 0
|
||||
* #define SL_INTERRUPT_MANAGER_S2_INTERRUPTS_IN_RAM 0
|
||||
* @endcode
|
||||
*
|
||||
* @note The SL_INTERRUPT_MANAGER_S2_INTERRUPTS_IN_RAM configuration is only available
|
||||
* on series 2. Enabling the S2_INTERRUPTS_IN_RAM configuration will tell the Interrupt Manager
|
||||
* to copy the interrupt vector table from ROM to RAM and select it as the interrupt table.
|
||||
* On newer series this feature is always enabled.
|
||||
*
|
||||
* ## The API
|
||||
*
|
||||
* This section contains brief descriptions of the functions in the API. For more
|
||||
* information on input and output parameters and return values,
|
||||
* click on the hyperlinked function names.
|
||||
*
|
||||
* @ref sl_interrupt_manager_disable_interrupts and @ref sl_interrupt_manager_enable_interrupts()
|
||||
* are used to prevent interrupts from executing during a certain timelapse.
|
||||
*
|
||||
* @ref sl_interrupt_manager_is_irq_disabled, @ref sl_interrupt_manager_is_irq_blocked
|
||||
* are used to know the status of an interrupt, either if it's disabled or blocked by one of the
|
||||
* following reasons: priority masking, disabling or an active interrupt of higher priority
|
||||
* is executing.
|
||||
*
|
||||
* @ref sl_interrupt_manager_is_irq_pending, @ref sl_interrupt_manager_set_irq_pending and
|
||||
* @ref sl_interrupt_manager_clear_irq_pending
|
||||
* are used for control and query of external interrupt source pending status.
|
||||
*
|
||||
* @ref sl_interrupt_manager_get_irq_priority and @ref sl_interrupt_manager_set_irq_priority
|
||||
* are used to get or set the priority for a specific interrupt.
|
||||
*
|
||||
* ## Priority Stratification
|
||||
* With the Interrupt Manager service and more generally in the Simplicity SDK, there are multiple distinct
|
||||
* levels of priority stratification.
|
||||
*
|
||||
* Each of these has their own characteristics and purposes.
|
||||
* For example, the higher priority group is considered to not be able to call kernel, power manager
|
||||
* or protocol stacks functions. They will only be impacted by critical sections (general interrupt
|
||||
* disable) but will be above atomic base interrupt priority level for execution. The higher level
|
||||
* is considered to be between 0 and 2 and the base interrupt priority level is 3.
|
||||
*
|
||||
* In the normal priority group you will find most application interrupts and such interrupts will be
|
||||
* the ones that will make calls to more features such as kernel, power manager and protocol stacks API.
|
||||
* It is this way because they are less deterministic than the "higher priority interrupts".
|
||||
*
|
||||
* <table>
|
||||
* <caption id="interrupt_priority_strat">Priority stratification inside SDK</caption>
|
||||
* <tr><th>Priority<th>Purpose
|
||||
* <tr><td>0 - 2 (Highest)<td>
|
||||
* <ul>
|
||||
* <li>No Kernel calls
|
||||
* <li>No Power Manager calls
|
||||
* <li>Not maskable by atomic sections
|
||||
* </ul>
|
||||
* <tr><td>3 - 7 (Normal)<td>
|
||||
* <ul>
|
||||
* <li>kernel calls
|
||||
* <li>power manager
|
||||
* <li>protocol stacks API
|
||||
* </ul>
|
||||
* <tr><td>7 (Lowest)<td>
|
||||
* <ul>
|
||||
* <li>PendSV level of priority
|
||||
* </ul>
|
||||
* </table>
|
||||
* @{
|
||||
******************************************************************************/
|
||||
|
||||
/// @brief sl_interrupt_manager interrupt handler function.
|
||||
typedef void(*sl_interrupt_manager_irq_handler_t)(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Initialize interrupt controller hardware and initialise vector table
|
||||
* in RAM.
|
||||
*
|
||||
* @note
|
||||
* The interrupt manager init function will perform the initialization only
|
||||
* once even if it's called multiple times.
|
||||
******************************************************************************/
|
||||
void sl_interrupt_manager_init(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Reset the cpu core.
|
||||
******************************************************************************/
|
||||
void sl_interrupt_manager_reset_system(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Disable interrupts.
|
||||
******************************************************************************/
|
||||
void sl_interrupt_manager_disable_interrupts(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Enable interrupts.
|
||||
******************************************************************************/
|
||||
void sl_interrupt_manager_enable_interrupts(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Disable interrupt for an interrupt source.
|
||||
*
|
||||
* @param[in] irqn
|
||||
* The interrupt number of the interrupt source.
|
||||
******************************************************************************/
|
||||
void sl_interrupt_manager_disable_irq(int32_t irqn);
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Enable interrupt for an interrupt source.
|
||||
*
|
||||
* @param[in] irqn
|
||||
* The interrupt number of the interrupt source.
|
||||
******************************************************************************/
|
||||
void sl_interrupt_manager_enable_irq(int32_t irqn);
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Check if an interrupt is disabled.
|
||||
*
|
||||
* @param[in] irqn
|
||||
* The interrupt number of the interrupt source.
|
||||
*
|
||||
* @return
|
||||
* True if the interrupt is disabled.
|
||||
******************************************************************************/
|
||||
bool sl_interrupt_manager_is_irq_disabled(int32_t irqn);
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Check if a specific interrupt is blocked.
|
||||
*
|
||||
* @note
|
||||
* The function return true if the IRQ is disabled.
|
||||
*
|
||||
* @param[in] irqn
|
||||
* The interrupt number of the interrupt source.
|
||||
*
|
||||
* @return
|
||||
* True if the interrupt is disabled or blocked.
|
||||
******************************************************************************/
|
||||
bool sl_interrupt_manager_is_irq_blocked(int32_t irqn);
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Get Pending Interrupt
|
||||
*
|
||||
* @note
|
||||
* Read the pending status of a specified interrupt and returns it status.
|
||||
*
|
||||
* @param[in] irqn
|
||||
* The interrupt number of the interrupt source.
|
||||
*
|
||||
* @return
|
||||
* false Interrupt status is not pending.
|
||||
* true Interrupt status is pending.
|
||||
******************************************************************************/
|
||||
bool sl_interrupt_manager_is_irq_pending(int32_t irqn);
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Set interrupt status to pending.
|
||||
*
|
||||
* @note
|
||||
* Sets an interrupt pending status to true.
|
||||
*
|
||||
* @param[in] irqn
|
||||
* The interrupt number of the interrupt source.
|
||||
******************************************************************************/
|
||||
void sl_interrupt_manager_set_irq_pending(int32_t irqn);
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Clear Pending Interrupt
|
||||
*
|
||||
* @details
|
||||
* Clear an interrupt pending status
|
||||
*
|
||||
* @param[in] irqn
|
||||
* The interrupt number of the interrupt source.
|
||||
*
|
||||
* @note
|
||||
* irqn must not be negative.
|
||||
*******************************************************************************/
|
||||
void sl_interrupt_manager_clear_irq_pending(int32_t irqn);
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Set the interrupt handler of an interrupt source.
|
||||
*
|
||||
* @note
|
||||
* This function depends on a RAM based interrupt vector table, i.e.
|
||||
* SL_INTERRUPT_MANAGER_S2_INTERRUPTS_IN_RAM must be true. Or the device
|
||||
* must be Series 3.
|
||||
*
|
||||
* @param[in] irqn
|
||||
* The interrupt number of the interrupt source.
|
||||
*
|
||||
* @param[in] handler
|
||||
* The new interrupt handler for the interrupt source.
|
||||
*
|
||||
* @return
|
||||
* The prior interrupt handler for the interrupt source.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_interrupt_manager_set_irq_handler(int32_t irqn,
|
||||
sl_interrupt_manager_irq_handler_t handler);
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Get the interrupt preemption priority of an interrupt source.
|
||||
*
|
||||
* @note
|
||||
* The number of priority levels is platform dependent.
|
||||
*
|
||||
* @param[in] irqn
|
||||
* The interrupt number of the interrupt source.
|
||||
*
|
||||
* @return
|
||||
* The interrupt priority for the interrupt source.
|
||||
* Value 0 denotes the highest priority.
|
||||
******************************************************************************/
|
||||
uint32_t sl_interrupt_manager_get_irq_priority(int32_t irqn);
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Set the interrupt preemption priority of an interrupt source.
|
||||
*
|
||||
* @note
|
||||
* The number of priority levels is platform dependent.
|
||||
*
|
||||
* @param[in] irqn
|
||||
* The interrupt number of the interrupt source.
|
||||
*
|
||||
* @param[in] priority
|
||||
* The new interrupt priority for the interrupt source.
|
||||
* Value 0 denotes the highest priority.
|
||||
******************************************************************************/
|
||||
void sl_interrupt_manager_set_irq_priority(int32_t irqn, uint32_t priority);
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Increase the interrupt preemption priority of an interrupt source.
|
||||
* relative to the default priority.
|
||||
*
|
||||
* @details
|
||||
* This function is useful to be architecture agnostic with priority values.
|
||||
*
|
||||
* Usage:
|
||||
* new_prio = sl_interrupt_manager_increase_irq_priority_from_default(IRQn, 1);
|
||||
*
|
||||
* This will increase the priority of IRQn by 1.
|
||||
*
|
||||
* @param[in] irqn
|
||||
* The irq to change the priority.
|
||||
*
|
||||
* @param[in] diff
|
||||
* The relative difference.
|
||||
******************************************************************************/
|
||||
void sl_interrupt_manager_increase_irq_priority_from_default(int32_t irqn, uint32_t diff);
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Decrease the interrupt preemption priority of an interrupt source
|
||||
* relative to the default priority.
|
||||
*
|
||||
* @details
|
||||
* This function is useful to be architecture agnostic with priority values.
|
||||
*
|
||||
* Usage:
|
||||
* new_prio = sl_interrupt_manager_decrease_irq_priority_from_default(IRQn, 1);
|
||||
*
|
||||
* This will decrease the priority of IRQn by 1.
|
||||
*
|
||||
* @param[in] irqn
|
||||
* The irq to change the priority.
|
||||
*
|
||||
* @param[in] diff
|
||||
* The relative difference.
|
||||
******************************************************************************/
|
||||
void sl_interrupt_manager_decrease_irq_priority_from_default(int32_t irqn, uint32_t diff);
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Get the default interrupt preemption priority value.
|
||||
*
|
||||
* @return
|
||||
* The default priority.
|
||||
******************************************************************************/
|
||||
uint32_t sl_interrupt_manager_get_default_priority(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Get the highest interrupt preemption priority value.
|
||||
*
|
||||
* @return
|
||||
* The highest priority value.
|
||||
******************************************************************************/
|
||||
uint32_t sl_interrupt_manager_get_highest_priority(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Get the lowest interrupt preemption priority value.
|
||||
*
|
||||
* @return
|
||||
* The lowest priority value.
|
||||
******************************************************************************/
|
||||
uint32_t sl_interrupt_manager_get_lowest_priority(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Get the interrupt active status.
|
||||
*
|
||||
* @param[in] irqn
|
||||
* The interrupt number of the interrupt source.
|
||||
*
|
||||
* @return
|
||||
* The interrupt active status.
|
||||
******************************************************************************/
|
||||
uint32_t sl_interrupt_manager_get_active_irq(int32_t irqn);
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Get the current ISR table.
|
||||
*
|
||||
* @details
|
||||
* Depending on the configuration of the Interrupt Manager, this table of
|
||||
* ISRs may be in RAM or in FLASH, and each ISR may or may not be wrapped by
|
||||
* enter/exit hooks.
|
||||
*
|
||||
* @return
|
||||
* The current ISR table.
|
||||
******************************************************************************/
|
||||
sl_interrupt_manager_irq_handler_t* sl_interrupt_manager_get_isr_table(void);
|
||||
|
||||
/** @} (end addtogroup interrupt_manager) */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SL_INTERRUPT_MANAGER_H */
|
||||
@@ -0,0 +1,601 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief Interrupt manager API to enable disable interrupts.
|
||||
*******************************************************************************
|
||||
* # License
|
||||
* <b>Copyright 2023 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 "sli_interrupt_manager.h"
|
||||
#include "sl_core.h"
|
||||
#include "sl_assert.h"
|
||||
#include "em_device.h"
|
||||
|
||||
#if defined(SL_COMPONENT_CATALOG_PRESENT)
|
||||
#include <sl_component_catalog.h>
|
||||
#endif
|
||||
|
||||
#if defined(SL_CATALOG_CODE_CLASSIFICATION_VALIDATOR_PRESENT)
|
||||
#include "sli_code_classification_validator.h"
|
||||
#endif
|
||||
|
||||
#if defined(_SILICON_LABS_32B_SERIES_2)
|
||||
#include "sl_interrupt_manager_s2_config.h"
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
********************************* DEFINES *********************************
|
||||
******************************************************************************/
|
||||
#define CORTEX_INTERRUPTS (16)
|
||||
#define TOTAL_INTERRUPTS (CORTEX_INTERRUPTS + EXT_IRQ_COUNT)
|
||||
|
||||
#define LOWEST_NVIC_PRIORITY ((1U << __NVIC_PRIO_BITS) - 1U)
|
||||
#define SL_INTERRUPT_MANAGER_DEFAULT_PRIORITY 5U
|
||||
|
||||
// Use same alignement as IAR
|
||||
#define VECTOR_TABLE_ALIGNMENT (512)
|
||||
|
||||
// Interrupt vector placement is in RAM
|
||||
#if (defined(SL_INTERRUPT_MANAGER_S2_INTERRUPTS_IN_RAM) \
|
||||
&& (SL_INTERRUPT_MANAGER_S2_INTERRUPTS_IN_RAM == 1)) \
|
||||
|| defined(SL_CATALOG_INTERRUPT_MANAGER_VECTOR_TABLE_IN_RAM_PRESENT)
|
||||
#define VECTOR_TABLE_IN_RAM (1)
|
||||
#endif
|
||||
|
||||
#if defined(SL_CATALOG_INTERRUPT_MANAGER_HOOKS_PRESENT)
|
||||
#define SL_INTERRUPT_MANAGER_ENABLE_HOOKS (1)
|
||||
#endif
|
||||
|
||||
// Interrupt vector table need to be in a different section of RAM for Cortex-M55.
|
||||
#if defined(__CM55_REV)
|
||||
#define RAM_BASE SRAM_BASE // ITCM_RAM_BASE
|
||||
#define RAM_SIZE SRAM_SIZE // ITCM_RAM_SIZE
|
||||
#if defined(__GNUC__)
|
||||
#define VECTOR_TABLE_SECTION __attribute__((section(".vector_table_ram")))
|
||||
#else
|
||||
#define VECTOR_TABLE_SECTION _Pragma("location =\".vector_table_ram\"")
|
||||
#endif
|
||||
#else
|
||||
#define RAM_BASE SRAM_BASE
|
||||
#define RAM_SIZE SRAM_SIZE
|
||||
#define VECTOR_TABLE_SECTION
|
||||
#endif
|
||||
|
||||
#if defined(VECTOR_TABLE_IN_RAM)
|
||||
|
||||
#if defined(__GNUC__)
|
||||
// Create a vector table in RAM aligned to 512.
|
||||
static sl_interrupt_manager_irq_handler_t vector_table_ram[TOTAL_INTERRUPTS] __attribute__((aligned(VECTOR_TABLE_ALIGNMENT) )) VECTOR_TABLE_SECTION;
|
||||
#elif defined(__ICCARM__)
|
||||
#pragma data_alignment = VECTOR_TABLE_ALIGNMENT
|
||||
static sl_interrupt_manager_irq_handler_t vector_table_ram[TOTAL_INTERRUPTS] VECTOR_TABLE_SECTION;
|
||||
#endif /* defined(__GNUC__) */
|
||||
|
||||
#if defined(SL_INTERRUPT_MANAGER_ENABLE_HOOKS)
|
||||
// When interrupt manager hooks are enabled, the actual vector table (either in
|
||||
// ram or in flash) will call an ISR wrapper. The actual ISRs will be registered
|
||||
// and called from the wrapped_vector_table.
|
||||
#if defined(__GNUC__)
|
||||
static sl_interrupt_manager_irq_handler_t wrapped_vector_table[TOTAL_INTERRUPTS] __attribute__((aligned(VECTOR_TABLE_ALIGNMENT) )) VECTOR_TABLE_SECTION;
|
||||
#elif defined(__ICCARM__)
|
||||
#pragma data_alignment = VECTOR_TABLE_ALIGNMENT
|
||||
static sl_interrupt_manager_irq_handler_t wrapped_vector_table[TOTAL_INTERRUPTS] VECTOR_TABLE_SECTION;
|
||||
#endif /* defined(__GNUC__) */
|
||||
#endif /* SL_INTERRUPT_MANAGER_ENABLE_HOOKS */
|
||||
|
||||
#endif /* VECTOR_TABLE_IN_RAM */
|
||||
|
||||
/*******************************************************************************
|
||||
***************************** PROTOTYPES ***********************************
|
||||
******************************************************************************/
|
||||
static void enable_interrupt(int32_t irqn);
|
||||
static void disable_interrupt(int32_t irqn);
|
||||
static void set_priority(int32_t irqn, uint32_t priority);
|
||||
static uint32_t get_priority(int32_t irqn);
|
||||
|
||||
#if defined(SL_INTERRUPT_MANAGER_ENABLE_HOOKS)
|
||||
#if defined(SL_CATALOG_CODE_CLASSIFICATION_VALIDATOR_PRESENT)
|
||||
CCV_SECTION
|
||||
#endif
|
||||
static void sli_interrupt_manager_isr_wrapper(void);
|
||||
#endif /* SL_INTERRUPT_MANAGER_HOOKS */
|
||||
|
||||
/*******************************************************************************
|
||||
***************************** VARIABLES ***********************************
|
||||
******************************************************************************/
|
||||
|
||||
// Initialization flag.
|
||||
static bool is_interrupt_manager_initialized = false;
|
||||
|
||||
/*******************************************************************************
|
||||
***************************** FUNCTIONS ***********************************
|
||||
******************************************************************************/
|
||||
|
||||
#if defined(VECTOR_TABLE_IN_RAM)
|
||||
#if defined(SL_INTERRUPT_MANAGER_ENABLE_HOOKS)
|
||||
|
||||
__WEAK void sl_interrupt_manager_irq_enter_hook(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
__WEAK void sl_interrupt_manager_irq_exit_hook(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static void sli_interrupt_manager_isr_wrapper(void)
|
||||
{
|
||||
uint32_t irqn = (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk);
|
||||
sl_interrupt_manager_irq_enter_hook();
|
||||
wrapped_vector_table[irqn]();
|
||||
sl_interrupt_manager_irq_exit_hook();
|
||||
}
|
||||
|
||||
#endif /* SL_INTERRUPT_MANAGER_HOOKS */
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Set a new RAM based interrupt vector table.
|
||||
******************************************************************************/
|
||||
sl_interrupt_manager_irq_handler_t *sli_interrupt_manager_set_irq_table(sl_interrupt_manager_irq_handler_t *table,
|
||||
uint32_t handler_count)
|
||||
{
|
||||
sl_interrupt_manager_irq_handler_t * current;
|
||||
|
||||
EFM_ASSERT(((uint32_t)table >= RAM_BASE) && (uint32_t)table < (RAM_BASE + RAM_SIZE));
|
||||
|
||||
// ASSERT if misaligned with respect to the VTOR register implementation.
|
||||
EFM_ASSERT(((uint32_t)table & ~SCB_VTOR_TBLOFF_Msk) == 0U);
|
||||
|
||||
// ASSERT if misaligned with respect to the vector table size.
|
||||
// The vector table address must be aligned at its size rounded up to nearest 2^n.
|
||||
EFM_ASSERT(((uint32_t)table
|
||||
& ((1UL << (32UL - __CLZ((handler_count * 4UL) - 1UL))) - 1UL))
|
||||
== 0UL);
|
||||
|
||||
// Disable all interrupts while updating the vector table
|
||||
sl_interrupt_manager_disable_interrupts();
|
||||
|
||||
current = (sl_interrupt_manager_irq_handler_t*)SCB->VTOR;
|
||||
|
||||
SCB->VTOR = (uint32_t)table;
|
||||
|
||||
// Make sure all explicit memory access are complete before proceding.
|
||||
__DSB();
|
||||
|
||||
sl_interrupt_manager_enable_interrupts();
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
#endif /* VECTOR_TABLE_IN_RAM */
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Initialize interrupt controller hardware and initialise vector table in RAM.
|
||||
*
|
||||
* @note
|
||||
* The interrupt manager init function will perform the initialization only
|
||||
* once even if it's called multiple times.
|
||||
******************************************************************************/
|
||||
void sl_interrupt_manager_init(void)
|
||||
{
|
||||
CORE_DECLARE_IRQ_STATE;
|
||||
|
||||
CORE_ENTER_ATOMIC();
|
||||
|
||||
if (!is_interrupt_manager_initialized) {
|
||||
is_interrupt_manager_initialized = true;
|
||||
CORE_EXIT_ATOMIC();
|
||||
} else {
|
||||
CORE_EXIT_ATOMIC();
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(VECTOR_TABLE_IN_RAM)
|
||||
|
||||
sl_interrupt_manager_irq_handler_t* current;
|
||||
|
||||
CORE_ENTER_CRITICAL();
|
||||
|
||||
current = (sl_interrupt_manager_irq_handler_t*)SCB->VTOR;
|
||||
|
||||
// copy ROM vector table to RAM table
|
||||
for (uint32_t i = 0; i < TOTAL_INTERRUPTS; i++) {
|
||||
#if defined(SL_INTERRUPT_MANAGER_ENABLE_HOOKS)
|
||||
wrapped_vector_table[i] = current[i];
|
||||
if ( i >= CORTEX_INTERRUPTS ) {
|
||||
vector_table_ram[i] = sli_interrupt_manager_isr_wrapper;
|
||||
} else {
|
||||
vector_table_ram[i] = current[i];
|
||||
}
|
||||
#else
|
||||
vector_table_ram[i] = current[i];
|
||||
#endif
|
||||
}
|
||||
|
||||
// Set RAM table as irq table.
|
||||
sli_interrupt_manager_set_irq_table(vector_table_ram, TOTAL_INTERRUPTS);
|
||||
|
||||
CORE_EXIT_CRITICAL();
|
||||
|
||||
#endif /* VECTOR_TABLE_IN_RAM */
|
||||
|
||||
for (IRQn_Type i = SVCall_IRQn; i < EXT_IRQ_COUNT; i++) {
|
||||
sl_interrupt_manager_set_irq_priority(i, SL_INTERRUPT_MANAGER_DEFAULT_PRIORITY);
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Reset the cpu core.
|
||||
******************************************************************************/
|
||||
void sl_interrupt_manager_reset_system(void)
|
||||
{
|
||||
CORE_RESET_SYSTEM();
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Disable interrupts.
|
||||
******************************************************************************/
|
||||
void sl_interrupt_manager_disable_interrupts(void)
|
||||
{
|
||||
__disable_irq();
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Enable interrupts.
|
||||
******************************************************************************/
|
||||
void sl_interrupt_manager_enable_interrupts(void)
|
||||
{
|
||||
__enable_irq();
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Disable interrupt for an interrupt source.
|
||||
******************************************************************************/
|
||||
void sl_interrupt_manager_disable_irq(int32_t irqn)
|
||||
{
|
||||
EFM_ASSERT((irqn >= 0) && (irqn <= EXT_IRQ_COUNT));
|
||||
|
||||
disable_interrupt(irqn);
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Enable interrupt for an interrupt source.
|
||||
******************************************************************************/
|
||||
void sl_interrupt_manager_enable_irq(int32_t irqn)
|
||||
{
|
||||
EFM_ASSERT((irqn >= 0) && (irqn <= EXT_IRQ_COUNT));
|
||||
|
||||
enable_interrupt(irqn);
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Check if an interrupt is disabled.
|
||||
******************************************************************************/
|
||||
bool sl_interrupt_manager_is_irq_disabled(int32_t irqn)
|
||||
{
|
||||
EFM_ASSERT((irqn >= 0) && (irqn < EXT_IRQ_COUNT));
|
||||
|
||||
return (NVIC->ISER[irqn >> 5U] & (1UL << (irqn & 0x1FUL))) == 0UL;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Check if an interrupt is disabled or blocked.
|
||||
******************************************************************************/
|
||||
bool sl_interrupt_manager_is_irq_blocked(int32_t irqn)
|
||||
{
|
||||
uint32_t irq_priority, active_irq;
|
||||
|
||||
#if (__CORTEX_M >= 3)
|
||||
uint32_t basepri;
|
||||
|
||||
EFM_ASSERT((irqn >= MemoryManagement_IRQn)
|
||||
&& (irqn < (IRQn_Type)EXT_IRQ_COUNT));
|
||||
#else
|
||||
EFM_ASSERT((irqn >= SVCall_IRQn) && ((IRQn_Type)irqn < EXT_IRQ_COUNT));
|
||||
#endif
|
||||
|
||||
if ((__get_PRIMASK() & 1U) != 0U) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (sl_interrupt_manager_is_irq_disabled(irqn)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
irq_priority = get_priority(irqn);
|
||||
|
||||
#if (__CORTEX_M >= 3)
|
||||
basepri = __get_BASEPRI();
|
||||
|
||||
if ((basepri != 0U)
|
||||
&& (irq_priority >= (basepri >> (8U - __NVIC_PRIO_BITS)))) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
active_irq = (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) >> SCB_ICSR_VECTACTIVE_Pos;
|
||||
|
||||
if (active_irq != 0U) {
|
||||
if (irq_priority >= get_priority(active_irq - 16U)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Get Pending Interrupt.
|
||||
******************************************************************************/
|
||||
bool sl_interrupt_manager_is_irq_pending(int32_t irqn)
|
||||
{
|
||||
if (irqn >= 0) {
|
||||
return (NVIC->ISPR[(((uint32_t)irqn) >> 5UL)] & (1UL << (((uint32_t)irqn) & 0x1FUL))) != 0UL;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Set irq status to pending.
|
||||
******************************************************************************/
|
||||
void sl_interrupt_manager_set_irq_pending(int32_t irqn)
|
||||
{
|
||||
if (irqn >= 0) {
|
||||
NVIC->ISPR[(((uint32_t)irqn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)irqn) & 0x1FUL));
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Clear Pending Interrupt.
|
||||
******************************************************************************/
|
||||
void sl_interrupt_manager_clear_irq_pending(int32_t irqn)
|
||||
{
|
||||
if (irqn >= 0) {
|
||||
NVIC->ICPR[(((uint32_t)irqn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)irqn) & 0x1FUL));
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Set the interrupt handler of an interrupt source.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_interrupt_manager_set_irq_handler(int32_t irqn,
|
||||
sl_interrupt_manager_irq_handler_t handler)
|
||||
{
|
||||
#if defined(VECTOR_TABLE_IN_RAM)
|
||||
|
||||
uint32_t interrupt_status;
|
||||
sl_interrupt_manager_irq_handler_t *table;
|
||||
|
||||
CORE_DECLARE_IRQ_STATE;
|
||||
CORE_ENTER_CRITICAL();
|
||||
|
||||
if ((irqn < 0) || (irqn >= EXT_IRQ_COUNT)) {
|
||||
return SL_STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
interrupt_status = (uint32_t)(((NVIC->ISER[(((uint32_t)irqn) >> 5UL)] & (1UL << (((uint32_t)irqn) & 0x1FUL))) != 0UL) ? 1UL : 0UL);
|
||||
|
||||
// Disable irqn interrupt while updating the handler's address
|
||||
sl_interrupt_manager_disable_irq(irqn);
|
||||
|
||||
#if defined(SL_INTERRUPT_MANAGER_ENABLE_HOOKS)
|
||||
table = wrapped_vector_table;
|
||||
#else
|
||||
table = (sl_interrupt_manager_irq_handler_t*)SCB->VTOR;
|
||||
#endif /* SL_INTERRUPT_MANAGER_ENABLE_HOOKS */
|
||||
|
||||
// Make sure the VTOR points to a table in RAM.
|
||||
if (((uint32_t)table < RAM_BASE) || (uint32_t)table > (RAM_BASE + RAM_SIZE)) {
|
||||
return SL_STATUS_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
table[irqn + 16] = handler;
|
||||
|
||||
// Make sure all explicit memory access are complete before proceding.
|
||||
__DSB();
|
||||
__ISB();
|
||||
|
||||
CORE_EXIT_CRITICAL();
|
||||
|
||||
if (interrupt_status == 1) {
|
||||
sl_interrupt_manager_enable_irq(irqn);
|
||||
}
|
||||
|
||||
return SL_STATUS_OK;
|
||||
#else
|
||||
(void) irqn;
|
||||
(void) handler;
|
||||
return SL_STATUS_INVALID_CONFIGURATION;
|
||||
#endif /* VECTOR_TABLE_IN_RAM */
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Get the interrupt preemption priority of an interrupt source.
|
||||
******************************************************************************/
|
||||
uint32_t sl_interrupt_manager_get_irq_priority(int32_t irqn)
|
||||
{
|
||||
uint32_t irq_priority = 0;
|
||||
|
||||
EFM_ASSERT((irqn >= -CORTEX_INTERRUPTS) && (irqn <= EXT_IRQ_COUNT));
|
||||
|
||||
irq_priority = get_priority(irqn);
|
||||
|
||||
return irq_priority;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Set the interrupt preemption priority of an interrupt source.
|
||||
******************************************************************************/
|
||||
void sl_interrupt_manager_set_irq_priority(int32_t irqn, uint32_t priority)
|
||||
{
|
||||
EFM_ASSERT((irqn >= -CORTEX_INTERRUPTS) && (irqn <= EXT_IRQ_COUNT));
|
||||
EFM_ASSERT(priority <= LOWEST_NVIC_PRIORITY);
|
||||
|
||||
set_priority(irqn, priority);
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Increase the interrupt preemption priority of an interrupt source
|
||||
* relative to the default priority.
|
||||
******************************************************************************/
|
||||
void sl_interrupt_manager_increase_irq_priority_from_default(int32_t irqn, uint32_t diff)
|
||||
{
|
||||
uint32_t prio = sl_interrupt_manager_get_default_priority();
|
||||
sl_interrupt_manager_set_irq_priority(irqn, prio - diff);
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Decrease the interrupt preemption priority of an interrupt source.
|
||||
* relative to the default priority.
|
||||
******************************************************************************/
|
||||
void sl_interrupt_manager_decrease_irq_priority_from_default(int32_t irqn, uint32_t diff)
|
||||
{
|
||||
uint32_t prio = sl_interrupt_manager_get_default_priority();
|
||||
sl_interrupt_manager_set_irq_priority(irqn, prio + diff);
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Get the default interrupt preemption priority value.
|
||||
******************************************************************************/
|
||||
uint32_t sl_interrupt_manager_get_default_priority(void)
|
||||
{
|
||||
return SL_INTERRUPT_MANAGER_DEFAULT_PRIORITY;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Get the highest interrupt preemption priority value.
|
||||
******************************************************************************/
|
||||
uint32_t sl_interrupt_manager_get_highest_priority(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Get the lowest interrupt preemption priority value.
|
||||
******************************************************************************/
|
||||
uint32_t sl_interrupt_manager_get_lowest_priority(void)
|
||||
{
|
||||
return LOWEST_NVIC_PRIORITY;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Get the interrupt active status.
|
||||
******************************************************************************/
|
||||
uint32_t sl_interrupt_manager_get_active_irq(int32_t irqn)
|
||||
{
|
||||
if ((int32_t)(irqn) >= 0) {
|
||||
return((uint32_t)(((NVIC->IABR[(((uint32_t)irqn) >> 5UL)] & (1UL << (((uint32_t)irqn) & 0x1FUL))) != 0UL) ? 1UL : 0UL));
|
||||
} else {
|
||||
return(0U);
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Enable an interrupts on the current core
|
||||
******************************************************************************/
|
||||
void enable_interrupt(int32_t irqn)
|
||||
{
|
||||
if ((int32_t)(irqn) >= 0) {
|
||||
__COMPILER_BARRIER();
|
||||
NVIC->ISER[(((uint32_t)irqn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)irqn) & 0x1FUL));
|
||||
__COMPILER_BARRIER();
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Disable an interrupts on the current core
|
||||
******************************************************************************/
|
||||
void disable_interrupt(int32_t irqn)
|
||||
{
|
||||
if ((int32_t)(irqn) >= 0) {
|
||||
NVIC->ICER[(((uint32_t)irqn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)irqn) & 0x1FUL));
|
||||
__DSB();
|
||||
__ISB();
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Set the priority of an interrupt.
|
||||
******************************************************************************/
|
||||
void set_priority(int32_t irqn, uint32_t priority)
|
||||
{
|
||||
if (irqn >= 0) {
|
||||
NVIC->IPR[((uint32_t)irqn)] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL);
|
||||
} else {
|
||||
SCB->SHPR[(((uint32_t)irqn) & 0xFUL) - 4UL] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL);
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Get the priority of an interrupt.
|
||||
******************************************************************************/
|
||||
uint32_t get_priority(int32_t irqn)
|
||||
{
|
||||
if (irqn >= 0) {
|
||||
return(((uint32_t)NVIC->IPR[((uint32_t)irqn)] >> (8U - __NVIC_PRIO_BITS)));
|
||||
} else {
|
||||
return(((uint32_t)SCB->SHPR[(((uint32_t)irqn) & 0xFUL) - 4UL] >> (8U - __NVIC_PRIO_BITS)));
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Get the current table of ISRs.
|
||||
******************************************************************************/
|
||||
sl_interrupt_manager_irq_handler_t* sl_interrupt_manager_get_isr_table(void)
|
||||
{
|
||||
#if defined(SL_INTERRUPT_MANAGER_ENABLE_HOOKS)
|
||||
return wrapped_vector_table;
|
||||
#else
|
||||
return (sl_interrupt_manager_irq_handler_t*)SCB->VTOR;
|
||||
#endif /* SL_INTERRUPT_MANAGER_ENABLE_HOOKS */
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief Interrupt Manager API internal utility functions.
|
||||
*******************************************************************************
|
||||
* # License
|
||||
* <b>Copyright 2023 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_INTERRUPT_MANAGER_H
|
||||
#define SLI_INTERRUPT_MANAGER_H
|
||||
|
||||
#include "sl_interrupt_manager.h"
|
||||
#include "em_device.h"
|
||||
|
||||
#if defined(_SILICON_LABS_32B_SERIES_2)
|
||||
#include "sl_interrupt_manager_s2_config.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Set a new RAM based interrupt vector table.
|
||||
*
|
||||
* @details
|
||||
* This function will copy the existing vector table to a RAM area supplied
|
||||
* by the application and set the interrupt controller to use that.
|
||||
*
|
||||
* @note
|
||||
* The table RAM area must be aligned to a TBD byte boundary.
|
||||
*
|
||||
* @param[in] table
|
||||
* Base address of new table.
|
||||
*
|
||||
* @param[in] handler_count
|
||||
* The size of the table, unit is number of interrupt handlers.
|
||||
*
|
||||
* @return
|
||||
* The prior interrupt vector table address.
|
||||
******************************************************************************/
|
||||
#if defined(_SILICON_LABS_32B_SERIES_3) \
|
||||
|| (defined(SL_INTERRUPT_MANAGER_S2_INTERRUPTS_IN_RAM) \
|
||||
&& (SL_INTERRUPT_MANAGER_S2_INTERRUPTS_IN_RAM == 1))
|
||||
|
||||
sl_interrupt_manager_irq_handler_t *sli_interrupt_manager_set_irq_table(sl_interrupt_manager_irq_handler_t *table,
|
||||
uint32_t handler_count);
|
||||
|
||||
#endif
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Pre-interrupt hook.
|
||||
*
|
||||
* @details
|
||||
* This function is called before each interrupt service routine
|
||||
* when the interrupt manager hooks feature is enabled.
|
||||
*
|
||||
* @note
|
||||
* The function is weakly defined, and may be user-defined. By default, the
|
||||
* pre-interrupt hook is empty.
|
||||
******************************************************************************/
|
||||
void sl_interrupt_manager_irq_enter_hook(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Register post-interrupt hook.
|
||||
*
|
||||
* @details
|
||||
* This function is called after each interrupt service routine
|
||||
* when the interrupt manager hooks feature is enabled.
|
||||
*
|
||||
* @note
|
||||
* The function is weakly defined, and may be user-defined. By default, the
|
||||
* post-interrupt hook is empty.
|
||||
******************************************************************************/
|
||||
void sl_interrupt_manager_irq_exit_hook(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SL_INTERRUPT_MANAGER_H */
|
||||
286
Libs/platform/service/iostream/inc/sl_iostream.h
Normal file
286
Libs/platform/service/iostream/inc/sl_iostream.h
Normal file
@@ -0,0 +1,286 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief IO Stream.
|
||||
*******************************************************************************
|
||||
* # 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_IOSTREAM_H
|
||||
#define SL_IOSTREAM_H
|
||||
|
||||
#if defined(SL_COMPONENT_CATALOG_PRESENT)
|
||||
#include "sl_component_catalog.h"
|
||||
#endif
|
||||
#include "sl_enum.h"
|
||||
#include "sl_status.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/***************************************************************************//**
|
||||
* @addtogroup iostream I/O Stream
|
||||
* @brief I/O Stream can be used to read/write different formats of data to various streams.
|
||||
* The source files for I/O Stream platform software module are present under platform/services/iostream.
|
||||
* @details
|
||||
* ## Overview
|
||||
*
|
||||
* I/O Stream is a platform module software that provides Input/Output functionalities
|
||||
* by creating streams. Streams are abstractions allowing a uniform way to read/write
|
||||
* data regardless of the physical communication interface.
|
||||
*
|
||||
* I/O Stream offers many interfaces, see submodules for a list of all types available
|
||||
* and their specificities.You can load multiple streams in the project and you can
|
||||
* select the interface that must be used at runtime.Some interface type can also
|
||||
* be instantiated, meaning that you can have multiple instances of an interface
|
||||
* type which will be normally bound to a hardware peripheral.
|
||||
*
|
||||
* ## Initialization
|
||||
*
|
||||
* The I/O Stream core doesn't require any initialization. Instead each stream type has
|
||||
* their own initialization and their own configuration. See I/O Stream specific type
|
||||
* to know more about how to initialize a stream.
|
||||
*
|
||||
* Note that most stream will set itself as the default stream during their initialization.
|
||||
* Thus the initial default stream will be the last stream initialized.
|
||||
*
|
||||
* ## Default system-wide stream
|
||||
*
|
||||
* Multiple streams can be initialized in your application and you can configure a default
|
||||
* stream that must be used when no stream is specified. Also note that the default stream
|
||||
* will be used when calling printf and you can change the default stream at runtime.
|
||||
* The following defines should be used for the default stream:
|
||||
*
|
||||
* SL_IOSTREAM_STDIN
|
||||
* SL_IOSTREAM_STDOUT
|
||||
* SL_IOSTREAM_STDERR
|
||||
*
|
||||
* ## RTOS - Task's default stream
|
||||
*
|
||||
* In the case of an RTOS environment, each task can set its own stream. By default, the task
|
||||
* stream will be set to the system_wide default stream. From your task, you can change the
|
||||
* default stream assigned to your task without affecting the other tasks' stream.
|
||||
*
|
||||
* ## Printf
|
||||
*
|
||||
* I/O Stream provides third-party printf integrations. It can work with toolchain implementation
|
||||
* or with the tiny printf implementation for embedded system. The printf API doesn't have an
|
||||
* argument for specifying the stream to be used, so I/O Stream provides a printf API that takes
|
||||
* a stream as an argument and calls the configured third-party implementation of printf.
|
||||
*
|
||||
* @{
|
||||
******************************************************************************/
|
||||
|
||||
/// @cond DO_NOT_INCLUDE_WITH_DOXYGEN
|
||||
#define SL_IOSTREAM_STDIN 0 ///< Default input stream
|
||||
#define SL_IOSTREAM_STDOUT 0 ///< Default output stream
|
||||
#define SL_IOSTREAM_STDERR 0 ///< Default error stream
|
||||
/// @endcond
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Data Types
|
||||
|
||||
/// @brief Struct representing iostream operations.
|
||||
typedef struct {
|
||||
void *context; ///< context
|
||||
sl_status_t (*write)(void *context, const void *buffer, size_t buffer_length); ///< write
|
||||
sl_status_t (*read)(void *context, void *buffer, size_t buffer_length, size_t *bytes_read); ///< read
|
||||
} sl_iostream_t;
|
||||
|
||||
/// @brief Enumeration representing the possible types of iostream instances.
|
||||
SL_ENUM(sl_iostream_type_t){
|
||||
SL_IOSTREAM_TYPE_SWO = 0, ///< SWO Instance
|
||||
SL_IOSTREAM_TYPE_RTT = 1, ///< RTT Instance
|
||||
SL_IOSTREAM_TYPE_UART = 2, ///< USART Instance
|
||||
SL_IOSTREAM_TYPE_VUART = 3, ///< Vuart
|
||||
SL_IOSTREAM_TYPE_DEBUG_OUTPUT = 4, ///< Backchannel output Instance Type
|
||||
SL_IOSTREAM_TYPE_LOOPBACK = 5, ///< Loopback Instance
|
||||
SL_IOSTREAM_TYPE_UNDEFINED = 6, ///< Undefined Instance Type
|
||||
};
|
||||
|
||||
/// @brief Struct representing an I/O Stream instance.
|
||||
typedef struct {
|
||||
sl_iostream_t *handle; ///< iostream instance handle.
|
||||
char *name; ///< iostream instance name.
|
||||
sl_iostream_type_t type; ///< iostream instance type.
|
||||
uint8_t periph_id; ///< iostream peripheral id.
|
||||
sl_status_t (*init)(void); ///< iostream instance init function.
|
||||
} sl_iostream_instance_info_t;
|
||||
|
||||
/// @cond DO_NOT_INCLUDE_WITH_DOXYGEN
|
||||
// Special stream to be used when you want to avoid printing anything
|
||||
extern sl_iostream_t sl_iostream_null;
|
||||
/// @endcond
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Prototypes
|
||||
|
||||
/***************************************************************************//**
|
||||
* Set the stream as default I/O Stream.
|
||||
*
|
||||
* @param[in] stream I/O Stream to set as default.
|
||||
*
|
||||
* @return Status result
|
||||
******************************************************************************/
|
||||
sl_status_t sl_iostream_set_default(sl_iostream_t *stream);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Get the default I/O Stream configured.
|
||||
*
|
||||
* @return Status result
|
||||
******************************************************************************/
|
||||
sl_iostream_t *sl_iostream_get_default(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Configure the systemwide default stream.
|
||||
*
|
||||
* @param[in] stream I/O Stream to be used.
|
||||
*
|
||||
* @return Status result
|
||||
******************************************************************************/
|
||||
#if defined(SL_CATALOG_KERNEL_PRESENT) && !defined(SL_IOSTREAM_FORCE_BAREMETAL)
|
||||
sl_status_t sl_iostream_set_system_default(sl_iostream_t *stream);
|
||||
#else
|
||||
#define sl_iostream_set_system_default sl_iostream_set_default
|
||||
#endif
|
||||
|
||||
/***************************************************************************//**
|
||||
* Output data on a stream.
|
||||
*
|
||||
* @param[in] stream I/O Stream to be used.
|
||||
* SL_IOSTREAM_STDOUT; Default output stream will be used.
|
||||
* Pointer to specific stream; Specific stream will be used.
|
||||
*
|
||||
* @param[in] buffer Buffer that contains the data to output.
|
||||
*
|
||||
* @param[in] buffer_length Data length contained in the buffer.
|
||||
*
|
||||
* @return Status result
|
||||
******************************************************************************/
|
||||
sl_status_t sl_iostream_write(sl_iostream_t *stream,
|
||||
const void *buffer,
|
||||
size_t buffer_length);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Get data from a stream.
|
||||
*
|
||||
* @param[in] stream I/O Stream to be used.
|
||||
* SL_IOSTREAM_STDOUT; Default output stream will be used.
|
||||
* Pointer to specific stream; Specific stream will be used.
|
||||
*
|
||||
* @param[out] buffer Buffer that contains the data to output.
|
||||
*
|
||||
* @param[in] buffer_length Data length contained in the buffer.
|
||||
*
|
||||
* @param[out] bytes_read Data length copied to the buffer.
|
||||
*
|
||||
* @return Status result
|
||||
******************************************************************************/
|
||||
sl_status_t sl_iostream_read(sl_iostream_t *stream,
|
||||
void *buffer,
|
||||
size_t buffer_length,
|
||||
size_t *bytes_read);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Print a character on stream.
|
||||
*
|
||||
* @param[in] stream I/O Stream to be used:
|
||||
* SL_IOSTREAM_STDOUT; Default output stream will be used.
|
||||
* SL_IOSTREAM_STDERR; Default error output stream will be used.
|
||||
* Pointer to specific stream; Specific stream will be used.
|
||||
*
|
||||
* @param[in] c Character to print
|
||||
*
|
||||
* @return Status result
|
||||
******************************************************************************/
|
||||
sl_status_t sl_iostream_putchar(sl_iostream_t *stream,
|
||||
char c);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Print a character on stream.
|
||||
*
|
||||
* @param[in] stream I/O Stream to be used.
|
||||
* SL_IOSTREAM_STDIN; Default input stream will be used.
|
||||
* Pointer to specific stream; Specific stream will be used.
|
||||
*
|
||||
* @param[out] c Pointer to variable that will receive the character.
|
||||
*
|
||||
* @return Status result
|
||||
******************************************************************************/
|
||||
sl_status_t sl_iostream_getchar(sl_iostream_t *stream,
|
||||
char *c);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Print a formated string on stream.
|
||||
*
|
||||
* @param[in] stream I/O Stream to be used:
|
||||
* SL_IOSTREAM_STDOUT; Default output stream will be used.
|
||||
* SL_IOSTREAM_STDERR; Default error output stream will be used.
|
||||
* Pointer to specific stream; Specific stream will be used.
|
||||
*
|
||||
* @param[in] format String that contains the text to be written.
|
||||
*
|
||||
* @param[in] argp A value identifying a variable arguments list.
|
||||
*
|
||||
* @return Status result
|
||||
******************************************************************************/
|
||||
sl_status_t sl_iostream_vprintf(sl_iostream_t *stream,
|
||||
const char *format,
|
||||
va_list argp);
|
||||
|
||||
#if defined(__GNUC__)
|
||||
__attribute__((format(printf, 2, 3)))
|
||||
#endif
|
||||
|
||||
/***************************************************************************//**
|
||||
* Print a formated string on stream.
|
||||
*
|
||||
* @param[in] stream I/O Stream to be used:
|
||||
* SL_IOSTREAM_STDOUT; Default output stream will be used.
|
||||
* SL_IOSTREAM_STDERR; Default error output stream will be used.
|
||||
* Pointer to specific stream; Specific stream will be used.
|
||||
*
|
||||
* @param[in] format String that contains the text to be written.
|
||||
*
|
||||
* @param[in] ... Additional arguments.
|
||||
*
|
||||
* @return Status result
|
||||
******************************************************************************/
|
||||
sl_status_t sl_iostream_printf(sl_iostream_t *stream,
|
||||
const char *format,
|
||||
...);
|
||||
|
||||
/** @} (end addtogroup iostream) */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // SL_IOSTREAM_H
|
||||
112
Libs/platform/service/iostream/inc/sl_iostream_rtt.h
Normal file
112
Libs/platform/service/iostream/inc/sl_iostream_rtt.h
Normal file
@@ -0,0 +1,112 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief IO Stream RTT Component.
|
||||
*******************************************************************************
|
||||
* # 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_IOSTREAM_RTT_H
|
||||
#define SL_IOSTREAM_RTT_H
|
||||
|
||||
#include "sl_iostream.h"
|
||||
#include "sl_status.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/***************************************************************************//**
|
||||
* @addtogroup iostream
|
||||
* @{
|
||||
******************************************************************************/
|
||||
|
||||
/***************************************************************************//**
|
||||
* @addtogroup iostream_rtt I/O Stream RTT
|
||||
* @brief I/O Stream RTT
|
||||
* @details
|
||||
* ## Overview
|
||||
*
|
||||
* Real Time Transfer (RTT) is a bi-directional communication interface developed
|
||||
* by Segger and used with J-Link module. You need to have the Segger RTT library
|
||||
* in your project to use this stream. It is offered as a third-party module in
|
||||
* the Silicon Labs SDK.
|
||||
*
|
||||
* RTT module uses a control block structure located in RAM memory with a specific
|
||||
* ID so that it can be discovered when a connection is established via J-Link.
|
||||
* The control block references a ring buffer for each configured channel. You can
|
||||
* configure the number and size of the ring buffers at compile-time in
|
||||
* SEGGER_RTT_Conf.h configuration file. Please refer to Segger's documentation
|
||||
* for further information on RTT.
|
||||
*
|
||||
* Note that you should only use this stream in a development environment. You
|
||||
* should avoid using it in production.
|
||||
*
|
||||
* ## Initialization
|
||||
*
|
||||
* The stream sets itself as the default stream at the end of the initialization
|
||||
* function.You must reconfigure the default interface if you have multiple streams
|
||||
* in your project else the last stream initialized will be set as the system default
|
||||
* stream.
|
||||
*
|
||||
* ## Power manager integration
|
||||
*
|
||||
* Because RTT communication uses the J-link debug interface when going into EM2 or EM3,
|
||||
* the system will actually go into a special Energy Mode to maintain the debug
|
||||
* capabilities and the power consumption will still remain high. Therefore it is unwise
|
||||
* to keep a debug interface with RTT channel open if you want to test your power
|
||||
* consumption.
|
||||
*
|
||||
* ## Communication channel connection
|
||||
*
|
||||
* For connecting to the RTT channel you can use the tools provided by Segger or you
|
||||
* can open a telnet session and connect to the port 19021 using your host IP
|
||||
* address when the debugger is connected using USB and using J-Link debugger IP address
|
||||
* when your debugger is connected over ethernet.
|
||||
*
|
||||
* @{
|
||||
******************************************************************************/
|
||||
|
||||
extern sl_iostream_t *sl_iostream_rtt_handle; ///< sl_iostream_rtt_handle
|
||||
extern sl_iostream_instance_info_t sl_iostream_instance_rtt_info; ///< sl_iostream_instance_rtt_info
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Prototypes
|
||||
|
||||
/***************************************************************************//**
|
||||
* RTT Stream init.
|
||||
*
|
||||
* @return Status result
|
||||
******************************************************************************/
|
||||
sl_status_t sl_iostream_rtt_init(void);
|
||||
|
||||
/** @} (end addtogroup iostream_rtt) */
|
||||
/** @} (end addtogroup iostream) */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // SL_IOSTREAM_RTT_H
|
||||
303
Libs/platform/service/iostream/src/sl_iostream.c
Normal file
303
Libs/platform/service/iostream/src/sl_iostream.c
Normal file
@@ -0,0 +1,303 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief IO Stream.
|
||||
*******************************************************************************
|
||||
* # 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_iostream.h"
|
||||
#include "sl_status.h"
|
||||
#include "sl_assert.h"
|
||||
#include "sl_core.h"
|
||||
|
||||
#if defined(SL_CATALOG_KERNEL_PRESENT) && !defined(SL_IOSTREAM_FORCE_BAREMETAL)
|
||||
#include "cmsis_os2.h"
|
||||
#include "sli_cmsis_os2_ext_task_register.h"
|
||||
#endif
|
||||
|
||||
#if defined(SL_CATALOG_PRINTF_PRESENT)
|
||||
#include "printf.h"
|
||||
#else
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
******************************* DEFINES ***********************************
|
||||
******************************************************************************/
|
||||
|
||||
#if defined(SL_CATALOG_KERNEL_PRESENT) && !defined(SL_IOSTREAM_FORCE_BAREMETAL)
|
||||
#define TASK_REGISTER_ID_INVALID 0xFF
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
*************************** LOCAL VARIABLES ********************************
|
||||
******************************************************************************/
|
||||
|
||||
#if defined(SL_CATALOG_KERNEL_PRESENT) && !defined(SL_IOSTREAM_FORCE_BAREMETAL)
|
||||
static sli_task_register_id_t sli_task_register_id = TASK_REGISTER_ID_INVALID;
|
||||
static sl_iostream_t *sli_iostream_system_default = NULL;
|
||||
#endif
|
||||
static sl_iostream_t *sli_iostream_default = NULL;
|
||||
|
||||
sl_iostream_t sl_iostream_null = {
|
||||
.write = NULL,
|
||||
.read = NULL,
|
||||
.context = NULL
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
********************* LOCAL FUNCTION PROTOTYPES ***************************
|
||||
******************************************************************************/
|
||||
|
||||
#if defined(SL_CATALOG_PRINTF_PRESENT)
|
||||
static void stream_putchar(char character,
|
||||
void *arg);
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
************************** GLOBAL FUNCTIONS *******************************
|
||||
******************************************************************************/
|
||||
|
||||
/***************************************************************************//**
|
||||
* Registers default IO stream to be used
|
||||
******************************************************************************/
|
||||
sl_status_t sl_iostream_set_default(sl_iostream_t *stream)
|
||||
{
|
||||
#if defined(SL_CATALOG_KERNEL_PRESENT) && !defined(SL_IOSTREAM_FORCE_BAREMETAL)
|
||||
sli_task_register_id_t reg_id;
|
||||
sl_status_t status;
|
||||
#endif
|
||||
CORE_DECLARE_IRQ_STATE;
|
||||
|
||||
CORE_ENTER_CRITICAL();
|
||||
#if defined(SL_CATALOG_KERNEL_PRESENT) && !defined(SL_IOSTREAM_FORCE_BAREMETAL)
|
||||
if (osThreadGetId() != NULL) {
|
||||
reg_id = sli_task_register_id;
|
||||
if (reg_id == TASK_REGISTER_ID_INVALID) {
|
||||
status = sli_osTaskRegisterNew(®_id);
|
||||
EFM_ASSERT(status == SL_STATUS_OK);
|
||||
sli_task_register_id = reg_id;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
sli_iostream_default = stream;
|
||||
CORE_EXIT_CRITICAL();
|
||||
|
||||
#if defined(SL_CATALOG_KERNEL_PRESENT) && !defined(SL_IOSTREAM_FORCE_BAREMETAL)
|
||||
if (osThreadGetId() != NULL) {
|
||||
status = sli_osTaskRegisterSetValue(NULL, reg_id, (uint32_t)stream);
|
||||
EFM_ASSERT(status == SL_STATUS_OK);
|
||||
}
|
||||
#endif
|
||||
|
||||
return SL_STATUS_OK;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Get default IO stream configured
|
||||
******************************************************************************/
|
||||
sl_iostream_t *sl_iostream_get_default(void)
|
||||
{
|
||||
#if defined(SL_CATALOG_KERNEL_PRESENT) && !defined(SL_IOSTREAM_FORCE_BAREMETAL)
|
||||
sl_status_t status;
|
||||
sli_task_register_id_t reg_id;
|
||||
#endif
|
||||
sl_iostream_t *stream = NULL;
|
||||
CORE_DECLARE_IRQ_STATE;
|
||||
|
||||
CORE_ENTER_CRITICAL();
|
||||
#if defined(SL_CATALOG_KERNEL_PRESENT) && !defined(SL_IOSTREAM_FORCE_BAREMETAL)
|
||||
reg_id = sli_task_register_id;
|
||||
#endif
|
||||
stream = sli_iostream_default;
|
||||
CORE_EXIT_CRITICAL();
|
||||
|
||||
#if defined(SL_CATALOG_KERNEL_PRESENT) && !defined(SL_IOSTREAM_FORCE_BAREMETAL)
|
||||
if (osThreadGetId() != NULL) {
|
||||
if (reg_id != TASK_REGISTER_ID_INVALID) {
|
||||
uint32_t reg;
|
||||
|
||||
status = sli_osTaskRegisterGetValue(NULL, sli_task_register_id, ®);
|
||||
EFM_ASSERT(status == SL_STATUS_OK);
|
||||
|
||||
stream = (sl_iostream_t *)reg;
|
||||
}
|
||||
}
|
||||
if (stream == NULL) {
|
||||
CORE_ENTER_CRITICAL();
|
||||
stream = sli_iostream_system_default;
|
||||
CORE_EXIT_CRITICAL();
|
||||
}
|
||||
#endif
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Set systemwide default IO stream
|
||||
******************************************************************************/
|
||||
#if defined(SL_CATALOG_KERNEL_PRESENT) && !defined(SL_IOSTREAM_FORCE_BAREMETAL)
|
||||
sl_status_t sl_iostream_set_system_default(sl_iostream_t *stream)
|
||||
{
|
||||
sl_status_t status = SL_STATUS_OK;
|
||||
CORE_DECLARE_IRQ_STATE;
|
||||
|
||||
CORE_ENTER_CRITICAL();
|
||||
sli_iostream_system_default = stream;
|
||||
CORE_EXIT_CRITICAL();
|
||||
return status;
|
||||
}
|
||||
#endif
|
||||
|
||||
/***************************************************************************//**
|
||||
* Stream write implementation
|
||||
******************************************************************************/
|
||||
sl_status_t sl_iostream_write(sl_iostream_t *stream,
|
||||
const void *buffer,
|
||||
size_t buffer_length)
|
||||
{
|
||||
if (stream == SL_IOSTREAM_STDOUT) {
|
||||
stream = sl_iostream_get_default();
|
||||
}
|
||||
|
||||
if ((stream != NULL) && (stream->write != NULL)) {
|
||||
return stream->write(stream->context, buffer, buffer_length);
|
||||
} else {
|
||||
return SL_STATUS_INVALID_CONFIGURATION;
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Stream read implementation
|
||||
******************************************************************************/
|
||||
sl_status_t sl_iostream_read(sl_iostream_t *stream,
|
||||
void *buffer,
|
||||
size_t buffer_length,
|
||||
size_t *bytes_read)
|
||||
{
|
||||
size_t size;
|
||||
size_t *read_size = &size;
|
||||
|
||||
if (stream == SL_IOSTREAM_STDIN) {
|
||||
stream = sl_iostream_get_default();
|
||||
}
|
||||
|
||||
if (bytes_read != NULL) {
|
||||
read_size = bytes_read;
|
||||
}
|
||||
|
||||
if ((stream != NULL) && (stream->read != NULL)) {
|
||||
return stream->read(stream->context, buffer, buffer_length, read_size);
|
||||
} else {
|
||||
return SL_STATUS_INVALID_CONFIGURATION;
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Stream putchar implementation
|
||||
******************************************************************************/
|
||||
sl_status_t sl_iostream_putchar(sl_iostream_t *stream,
|
||||
char c)
|
||||
{
|
||||
return sl_iostream_write(stream, &c, 1);
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Stream getchar implementation
|
||||
******************************************************************************/
|
||||
sl_status_t sl_iostream_getchar(sl_iostream_t *stream,
|
||||
char *c)
|
||||
{
|
||||
return sl_iostream_read(stream, c, 1, NULL);
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Stream vprintf implementation
|
||||
******************************************************************************/
|
||||
sl_status_t sl_iostream_vprintf(sl_iostream_t *stream,
|
||||
const char *format,
|
||||
va_list argp)
|
||||
{
|
||||
#if !defined(SL_CATALOG_PRINTF_PRESENT)
|
||||
sl_iostream_t *default_stream;
|
||||
#endif
|
||||
sl_iostream_t *output_stream = stream;
|
||||
sl_status_t status = SL_STATUS_OK;
|
||||
int ret;
|
||||
|
||||
#if defined(SL_CATALOG_PRINTF_PRESENT)
|
||||
if (output_stream == SL_IOSTREAM_STDOUT) {
|
||||
output_stream = sl_iostream_get_default();
|
||||
}
|
||||
ret = vfctprintf(stream_putchar, output_stream, format, argp);
|
||||
#else
|
||||
if (output_stream == SL_IOSTREAM_STDOUT) {
|
||||
default_stream = sl_iostream_get_default();
|
||||
output_stream = default_stream;
|
||||
} else {
|
||||
default_stream = sl_iostream_get_default();
|
||||
if (default_stream != output_stream) {
|
||||
sl_iostream_set_default(output_stream);
|
||||
}
|
||||
}
|
||||
|
||||
ret = vprintf(format, argp);
|
||||
if (default_stream != output_stream) {
|
||||
sl_iostream_set_default(default_stream);
|
||||
}
|
||||
#endif
|
||||
if (ret <= 0) {
|
||||
status = SL_STATUS_OBJECT_WRITE;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Stream printf implementation
|
||||
******************************************************************************/
|
||||
sl_status_t sl_iostream_printf(sl_iostream_t *stream,
|
||||
const char *format,
|
||||
...)
|
||||
{
|
||||
sl_status_t status;
|
||||
va_list argp;
|
||||
va_start(argp, format);
|
||||
status = sl_iostream_vprintf(stream, format, argp);
|
||||
va_end(argp);
|
||||
return status;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* putchar implementation for sl_iostream_printf; called by fnctprintf()
|
||||
******************************************************************************/
|
||||
#if defined(SL_CATALOG_PRINTF_PRESENT)
|
||||
static void stream_putchar(char character,
|
||||
void *arg)
|
||||
{
|
||||
sl_iostream_putchar((sl_iostream_t *)arg, character);
|
||||
}
|
||||
#endif
|
||||
144
Libs/platform/service/iostream/src/sl_iostream_rtt.c
Normal file
144
Libs/platform/service/iostream/src/sl_iostream_rtt.c
Normal file
@@ -0,0 +1,144 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief IO Stream RTT Component.
|
||||
*******************************************************************************
|
||||
* # 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_iostream_rtt.h"
|
||||
//#include "SEGGER_RTT.h"
|
||||
#include "sl_status.h"
|
||||
|
||||
#if !defined(IOSTREAM_RTT_UP_MODE)
|
||||
#define IOSTREAM_RTT_UP_MODE SEGGER_RTT_MODE_NO_BLOCK_TRIM
|
||||
#endif
|
||||
|
||||
#if !defined(IOSTREAM_RTT_DOWN_MODE)
|
||||
#define IOSTREAM_RTT_DOWN_MODE SEGGER_RTT_MODE_NO_BLOCK_TRIM
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
********************* LOCAL FUNCTION PROTOTYPES ***************************
|
||||
******************************************************************************/
|
||||
|
||||
static sl_status_t rtt_write(void *context,
|
||||
const void *buffer,
|
||||
size_t buffer_length);
|
||||
|
||||
static sl_status_t rtt_read(void *context,
|
||||
void *buffer,
|
||||
size_t buffer_length,
|
||||
size_t *bytes_read);
|
||||
|
||||
/*******************************************************************************
|
||||
****************************** VARIABLES **********************************
|
||||
******************************************************************************/
|
||||
|
||||
static sl_iostream_t sl_iostream_rtt = {
|
||||
.read = rtt_read,
|
||||
.write = rtt_write,
|
||||
.context = NULL
|
||||
};
|
||||
|
||||
sl_iostream_t *sl_iostream_rtt_handle = &sl_iostream_rtt;
|
||||
|
||||
sl_iostream_instance_info_t sl_iostream_instance_rtt_info = {
|
||||
.handle = &sl_iostream_rtt,
|
||||
.name = "rtt",
|
||||
.type = SL_IOSTREAM_TYPE_RTT,
|
||||
.periph_id = 0,
|
||||
.init = sl_iostream_rtt_init,
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
************************** GLOBAL FUNCTIONS *******************************
|
||||
******************************************************************************/
|
||||
|
||||
/***************************************************************************//**
|
||||
* RTT Stream init.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_iostream_rtt_init(void)
|
||||
{
|
||||
//SEGGER_RTT_ConfigUpBuffer(0, NULL, NULL, 0, IOSTREAM_RTT_UP_MODE);
|
||||
//SEGGER_RTT_ConfigDownBuffer(0, NULL, NULL, 0, IOSTREAM_RTT_DOWN_MODE);
|
||||
sl_iostream_set_system_default(&sl_iostream_rtt);
|
||||
|
||||
return SL_STATUS_OK;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
************************** LOCAL FUNCTIONS ********************************
|
||||
******************************************************************************/
|
||||
|
||||
/***************************************************************************//**
|
||||
* Internal RTT stream write implementation
|
||||
******************************************************************************/
|
||||
static sl_status_t rtt_write(void *context,
|
||||
const void *buffer,
|
||||
size_t buffer_length)
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
sl_status_t status;
|
||||
(void)context;
|
||||
(void)ret;
|
||||
|
||||
//ret = SEGGER_RTT_Write(0, buffer, buffer_length);
|
||||
|
||||
#if ((IOSTREAM_RTT_UP_MODE == SEGGER_RTT_MODE_NO_BLOCK_TRIM) \
|
||||
|| (IOSTREAM_RTT_UP_MODE == SEGGER_RTT_MODE_NO_BLOCK_SKIP))
|
||||
status = SL_STATUS_OK; // Ignore error
|
||||
#else
|
||||
if (ret > 0) {
|
||||
status = SL_STATUS_OK;
|
||||
} else {
|
||||
status = SL_STATUS_IO;
|
||||
}
|
||||
#endif
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Internal RTT stream read implementation
|
||||
******************************************************************************/
|
||||
static sl_status_t rtt_read(void *context,
|
||||
void *buffer,
|
||||
size_t buffer_length,
|
||||
size_t *bytes_read)
|
||||
{
|
||||
sl_status_t status;
|
||||
(void)context;
|
||||
|
||||
// *bytes_read = SEGGER_RTT_Read(0, buffer, buffer_length);
|
||||
|
||||
if (*bytes_read > 0) {
|
||||
status = SL_STATUS_OK;
|
||||
} else {
|
||||
status = SL_STATUS_EMPTY;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
971
Libs/platform/service/memory_manager/inc/sl_memory_manager.h
Normal file
971
Libs/platform/service/memory_manager/inc/sl_memory_manager.h
Normal file
@@ -0,0 +1,971 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief Memory Manager Driver API definition.
|
||||
*******************************************************************************
|
||||
* # 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.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef SL_MEMORY_MANAGER_H_
|
||||
#define SL_MEMORY_MANAGER_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "sl_status.h"
|
||||
#include "sl_core.h"
|
||||
#include "sl_memory_manager_region.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**************************************************************************//**
|
||||
* @addtogroup memory_manager Memory Manager
|
||||
*
|
||||
* @details
|
||||
* ## Overview
|
||||
*
|
||||
* The Memory Manager is a platform-level software module that provides different
|
||||
* ways to perform runtime allocations, either one shot or dynamic.
|
||||
* The Memory Manager complements the toolchain linker by managing the RAM memory
|
||||
* not allocated/partitioned by the linker. It offers different constructs that
|
||||
* will help the different Silicon Labs SDK software modules and your application
|
||||
* to build, as much as possible, an efficient and optimized RAM layout. The main
|
||||
* Memory Manager constructs will be:
|
||||
* - A dynamic allocation API
|
||||
* - A memory pool API
|
||||
* - A dynamic reservation API
|
||||
*
|
||||
* The Memory Manager can be used in an RTOS context as it is thread-safe by
|
||||
* protecting adequately its internal shared resources.
|
||||
*
|
||||
* ## Initialization
|
||||
*
|
||||
* The initialization part includes the following configuration files:
|
||||
* - \b sl_memory_manager_region_config.h
|
||||
* - \b sl_memory_manager_config.h
|
||||
*
|
||||
* These header files offer a few configurations for the Memory Manager.
|
||||
* They use the CMSIS Configuration Wizard Annotations that can be rendered
|
||||
* by Simplicity Studio to set graphically the configuration settings value.
|
||||
*
|
||||
* The API function sl_memory_init() is used to initialize the Memory Manager
|
||||
* module. This function must be called early during your initialization sequence.
|
||||
* If the SL System component (@ref system) is used by your application, the
|
||||
* sl_memory_init() call will be added automatically to your initialization
|
||||
* sequence.
|
||||
*
|
||||
* \a sl_memory_manager_region_config.h allows to configure the stack size for
|
||||
* the application. The default value of 4096 bytes for SL_STACK_SIZE will
|
||||
* be used by the linker to allocate a stack zone in the RAM. In a baremetal
|
||||
* application, the stack size is bound to the value set by SL_STACK_SIZE.
|
||||
* So you should carefully size the stack in that case.
|
||||
* In an RTOS application, the stack size SL_STACK_SIZE will serve mainly for the
|
||||
* code running in the main() context until the kernel is launched. Once the kernel is
|
||||
* started, the different tasks' stacks, created upon tasks' creation, will allow
|
||||
* to save the different contexts (that is task, function, ISR contexts). The main
|
||||
* stack will be less active while the application's tasks are running.
|
||||
*
|
||||
* @note It is not possible to specify a minimum heap size via a configuration value
|
||||
* in \a sl_memory_manager_region_config.h. The GCC and IAR linker files define
|
||||
* a heap section in RAM that will be the last zone of the RAM partitioned by
|
||||
* the toolchain linker. The size of this heap zone will be the remaining
|
||||
* space of the RAM. If you need to perform some checks on the heap size, you
|
||||
* should do it at runtime using the Memory Manager \ref subsubsection-statistics
|
||||
* "statistics API". You cannot do it during the toolchain preprocessor time.
|
||||
*
|
||||
* ## Functionalities
|
||||
*
|
||||
* The Memory Manager offers different functionalities such as:
|
||||
* - Dynamically allocating and freeing blocks.
|
||||
* - Creating and deleting memory pools. Allocating and freeing fixed-size
|
||||
* blocks from a given pool.
|
||||
* - Reserving and releasing blocks.
|
||||
* - Getting statistics about the heap usage and the stack.
|
||||
* - Retargeting the standard C library memory functions malloc()/free()/
|
||||
* calloc()/realloc() to the Memory Manager ones.
|
||||
* - Overloading the C++ standard new/delete operators to the Memory Manager
|
||||
* malloc()/free()
|
||||
*
|
||||
* \subsubsection subsubsection-dynamic-allocation Dynamic Allocation
|
||||
* The dynamic allocation API allows to dynamically allocate and free memory blocks
|
||||
* of various sizes. The API supports the classic signatures of memory functions
|
||||
* malloc()/free()/calloc()/realloc() while also offering variants of the same
|
||||
* functions.
|
||||
*
|
||||
* <table>
|
||||
* <tr><th>Operation<th>Standard-Like Function<th>Variant Function
|
||||
* <tr><td>Allocating a block<td>sl_malloc()<td>
|
||||
* <ul>
|
||||
* <li>sl_memory_alloc()
|
||||
* <li>sl_memory_alloc_advanced()
|
||||
* </ul>
|
||||
* <tr><td>Freeing a block<td>sl_free()<td>sl_memory_free()
|
||||
* <tr><td>Allocating a block whose content is zero'ed<td>sl_calloc()<td>sl_memory_calloc()
|
||||
* <tr><td>Re-allocating a block<td>sl_realloc()<td>sl_memory_realloc()
|
||||
* </table>
|
||||
*
|
||||
* The variants functions \a sl_memory_xxxx() differs from the standard-like functions
|
||||
* with the following:
|
||||
* - They return an error code of type \a sl_status_t. You may want
|
||||
* to process any returned error code different from \a SL_STATUS_OK.
|
||||
* - They allow to specify a block alignment requirement in bytes. The alignment
|
||||
* can be any power-of-two values between 1 and 512 bytes inclusively. The default
|
||||
* block alignment the Memory Manager will use is 8 bytes to maximize CPU accesses
|
||||
* to allocated memory blocks.
|
||||
* - They allow to specify a block type as long-term or short-term (further explained
|
||||
* below). The Memory Manager allows to allocate a block from different ends of the heap
|
||||
* to limit the fragmentation.
|
||||
*
|
||||
* Allocating a block can be done by specifying your requested size with the simple
|
||||
* sl_malloc(). If you have a special alignment requirement, the function
|
||||
* sl_memory_alloc_advanced() is the one to use.
|
||||
* The Memory Manager will use a first fit algorithm to find the block fitting
|
||||
* the requested size. If the found block is too large, the allocator tries to split it
|
||||
* to create a new free block from the unwanted portion of the found block. The block
|
||||
* internal split operation helps to limit the internal fragmentation.
|
||||
*
|
||||
* The dynamic allocation API allows to specify the block type as long-term
|
||||
* (BLOCK_TYPE_LONG_TERM) or short-term (BLOCK_TYPE_SHORT_TERM) with the
|
||||
* functions sl_memory_alloc() or sl_memory_alloc_advanced().
|
||||
* The long-term (LT) allocations are allocated from the heap start,
|
||||
* while short-term (ST) ones are allocated from the heap end. LT/ST allocations
|
||||
* relate to the expected lifetime of the block allocation. LT blocks are used for
|
||||
* the full duration of the application or for something that is expected
|
||||
* to last a long time. For instance, a control data structure enabling the proper
|
||||
* functioning of a stack's layer, a driver, a part of the application layer.
|
||||
* ST blocks are used for something that is expected to be freed quite quickly.
|
||||
* For example, a received buffer that needs to be processed and once processed
|
||||
* will be freed.
|
||||
* Grouping your allocations as LT blocks and/or ST blocks can help to limit the
|
||||
* heap fragmentation.
|
||||
* Certain functions does not allow to indicate the block type. In that case,
|
||||
* a default type is selected by the allocator.
|
||||
*
|
||||
* <table>
|
||||
* <tr><th>Function<th>Block type
|
||||
* <tr><td>sl_malloc()<td>Long-term by default<td>
|
||||
* <tr><td>sl_memory_alloc()<td>Long-term or short-term<td>
|
||||
* <tr><td>sl_memory_alloc_advanced()<td>Long-term or short-term<td>
|
||||
* <tr><td>sl_calloc()<td>Long-term by default<td>
|
||||
* <tr><td>sl_memory_calloc()<td>Long-term or short-term<td>
|
||||
* <tr><td>sl_realloc()<td>Long-term by default<td>
|
||||
* <tr><td>sl_memory_realloc()<td>Long-term by default<td>
|
||||
* </table>
|
||||
*
|
||||
* Freeing a block is done by calling sl_free() or sl_memory_free(). sl_memory_free()
|
||||
* returns an error code of type sl_status_t that you may want to test. Passing a NULL
|
||||
* pointer to sl_free() or sl_memory_free() results in a neutral situation where the
|
||||
* free() function will do nothing. If the same block is freed twice, the function
|
||||
* sl_memory_free() will return an error. During the free operation, the function will
|
||||
* try to merge adjacent blocks to the block that is being freed in order to limit
|
||||
* the internal fragmentation. The adjacent blocks must, of course, not be in use
|
||||
* to be merged.
|
||||
*
|
||||
* If you want to get a block from the heap whose content has been initialized to zero
|
||||
* to avoid any garbage values, the function sl_calloc() or sl_memory_calloc() can be
|
||||
* called.
|
||||
*
|
||||
* If you need to reallocate a block, the function sl_realloc() or sl_memory_realloc()
|
||||
* should be called. Both versions allow to:
|
||||
* - Extend the block with the requested size greater than the original size.
|
||||
* - Reduce the block with the requested size smaller than the original size.
|
||||
* - Extend a different block with the requested size greater than the original size.
|
||||
*
|
||||
* The block can be moved elsewhere in the heap if it is impossible to extend it in its
|
||||
* current memory space. A reduced block will always stay in the original block space as the
|
||||
* allocator does not need to provide a different block.
|
||||
* The content of the reallocated memory block is preserved up to the lesser of the
|
||||
* new and old sizes, even if the block is moved to a new location. If the new size
|
||||
* is larger, the value of the newly allocated portion is indeterminate.
|
||||
* Some combinations of input parameters when calling sl_realloc() or sl_memory_realloc()
|
||||
* will lead to the same behavior as sl_malloc(), sl_memory_alloc() or sl_free(),
|
||||
* sl_memory_free() (cf. the sl_realloc() or sl_memory_realloc() function description
|
||||
* for more details about those combinations).
|
||||
*
|
||||
* The following code snippet shows a basic block allocation and
|
||||
* deallocation using the standard-like functions:
|
||||
* @code{.c}
|
||||
* uint8_t *ptr8;
|
||||
*
|
||||
* ptr8 = (uint8_t *)sl_malloc(200);
|
||||
* memset(ptr8, 0xAA, 100);
|
||||
* sl_free(ptr8);
|
||||
* @endcode
|
||||
*
|
||||
* This other code snippet shows the same basic block allocation and
|
||||
* deallocation using the variant functions:
|
||||
* @code{.c}
|
||||
* uint8_t *ptr8;
|
||||
* sl_status_t status;
|
||||
*
|
||||
* status = sl_memory_alloc(100, BLOCK_TYPE_LONG_TERM, (void **)&ptr8);
|
||||
* if (status != SL_STATUS_OK) {
|
||||
* // Process the error condition.
|
||||
* }
|
||||
*
|
||||
* memset(ptr8, 0xBB, 100);
|
||||
*
|
||||
* status = sl_memory_free(ptr8);
|
||||
* if (status != SL_STATUS_OK) {
|
||||
* // Process the error condition.
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* ### Memory Pool
|
||||
*
|
||||
* The memory pool API allows to:
|
||||
* - Create a pool composed of N number of fixed-size blocks: sl_memory_create_pool().
|
||||
* - Delete a pool: sl_memory_delete_pool().
|
||||
* - Get a block from the pool: sl_memory_pool_alloc().
|
||||
* - Free a pool's block: sl_memory_pool_free().
|
||||
*
|
||||
* Memory pools are convenient if you want to ensure a sort of guaranteed quotas
|
||||
* for some memory allocations situations. It is also more robust to unexpected
|
||||
* allocations errors as opposed to the dynamic allocation API in which a block
|
||||
* allocation can fail randomly if there is no free block to satisfy the requested
|
||||
* size.
|
||||
*
|
||||
* The memory pool API uses a pool handle. This handle is initialized when the pool
|
||||
* is created with sl_memory_create_pool(). Then this handle is passed as an input
|
||||
* parameter of the other functions. The handle can be allocated statically or
|
||||
* dynamically. A static pool handle means the handle of type
|
||||
* @ref sl_memory_pool_t "sl_memory_pool_t{}" is a global variable for example.
|
||||
* A dynamic pool handle means the handle is obtained from the heap itself by
|
||||
* calling the function sl_memory_pool_handle_alloc().The dynamic pool handle will
|
||||
* be freed with a call to sl_memory_pool_handle_free().
|
||||
*
|
||||
* The following code snippet shows a typical memory pool API sequence using
|
||||
* a static pool handle:
|
||||
* @code{.c}
|
||||
* uint8_t *ptr8;
|
||||
* sl_status_t status;
|
||||
* sl_memory_pool_t pool1_handle = { 0 };
|
||||
*
|
||||
* // Create a pool of 15 blocks whose size is 100 bytes for each block.
|
||||
* status = sl_memory_create_pool(100, 15, &pool1_handle);
|
||||
* if (status != SL_STATUS_OK) {
|
||||
* // Process the error condition.
|
||||
* }
|
||||
*
|
||||
* status = sl_memory_pool_alloc(&pool1_handle, (void **)&ptr8);
|
||||
* if (status != SL_STATUS_OK) {
|
||||
* // Process the error condition.
|
||||
* }
|
||||
*
|
||||
* memset(ptr8, 0xCC, 100);
|
||||
*
|
||||
* status = sl_memory_pool_free(&pool1_handle, ptr8);
|
||||
* if (status != SL_STATUS_OK) {
|
||||
* // Process the error condition.
|
||||
* }
|
||||
*
|
||||
* status = sl_memory_delete_pool(&pool1_handle);
|
||||
* if (status != SL_STATUS_OK) {
|
||||
* // Process the error condition.
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* This other code snippet presents the previous typical memory pool API sequence
|
||||
* using a dynamic pool handle:
|
||||
* @code{.c}
|
||||
* sl_status_t status;
|
||||
* sl_memory_pool_t *pool1_handle = NULL;
|
||||
*
|
||||
* status = sl_memory_pool_handle_alloc(&pool1_handle);
|
||||
* if (status != SL_STATUS_OK) {
|
||||
* // Process the error condition.
|
||||
* }
|
||||
*
|
||||
* // Create a pool of 15 blocks of 100 bytes in size.
|
||||
* status = sl_memory_create_pool(100, 15, &pool1_handle);
|
||||
* if (status != SL_STATUS_OK) {
|
||||
* // Process the error condition.
|
||||
* }
|
||||
*
|
||||
* // Get blocks from the pool, use them and free them once done.
|
||||
* ...
|
||||
*
|
||||
* status = sl_memory_delete_pool(&pool1_handle);
|
||||
* if (status != SL_STATUS_OK) {
|
||||
* // Process the error condition.
|
||||
* }
|
||||
*
|
||||
* status = sl_memory_pool_handle_free(pool1_handle);
|
||||
* if (status != SL_STATUS_OK) {
|
||||
* // Process the error condition.
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* ### Dynamic Reservation
|
||||
*
|
||||
* The dynamic reservation is a special construct allowing to reserve a block
|
||||
* of a given size with sl_memory_reserve_block() and to release it with
|
||||
* sl_memory_release_block(). The reserved block can then be used to any
|
||||
* application purposes. The reserved block will be taken from the
|
||||
* short-term section at the end of the heap.
|
||||
* Please note that the dynamic reservation API is not meant
|
||||
* to be used in the same way as the \ref subsubsection-dynamic-allocation
|
||||
* "dynamic allocation API".
|
||||
*
|
||||
* The dynamic reservation API uses a reservation handle. This handle is initialized
|
||||
* when the block is reserved with sl_memory_reserve_block(). Then this handle
|
||||
* is passed as an input parameter to the other functions. The handle can be
|
||||
* allocated statically or dynamically. A static reservation handle means the handle
|
||||
* of type @ref sl_memory_reservation_t "sl_memory_reservation_t{}" is a global
|
||||
* variable for example. A dynamic reservation handle means the handle is
|
||||
* obtained from the heap itself by calling the function
|
||||
* sl_memory_reservation_handle_alloc(). The dynamic reservaiton handle will be
|
||||
* freed with a call to sl_memory_reservation_handle_free().
|
||||
*
|
||||
* The following code snippet shows a typical dynamic reservation API sequence
|
||||
* using a static reservation handle:
|
||||
* @code{.c}
|
||||
* uint8_t *ptr8;
|
||||
* sl_status_t status;
|
||||
* sl_memory_reservation_t reservation_handle1 = { 0 };
|
||||
*
|
||||
* status = sl_memory_reserve_block(1024,
|
||||
* SL_MEMORY_BLOCK_ALIGN_8_BYTES,
|
||||
* reservation_handle1,
|
||||
* (void **)&ptr8);
|
||||
* if (status != SL_STATUS_OK) {
|
||||
* // Process the error condition.
|
||||
* }
|
||||
*
|
||||
* memset(ptr8, 0xDD, 1024);
|
||||
*
|
||||
* status = sl_memory_release_block(&reservation_handle1);
|
||||
* if (status != SL_STATUS_OK) {
|
||||
* // Process the error condition.
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* This other code snippet demonstrates the previous typical dynamic reservation API
|
||||
* sequence using a dynamic reservation handle:
|
||||
* @code{.c}
|
||||
* uint8_t *ptr8;
|
||||
* sl_status_t status;
|
||||
* sl_memory_reservation_t *reservation_handle1;
|
||||
*
|
||||
* status = sl_memory_reservation_handle_alloc(&reservation_handle1);
|
||||
* if (status != SL_STATUS_OK) {
|
||||
* // Process the error condition.
|
||||
* }
|
||||
*
|
||||
* status = sl_memory_reserve_block(1024,
|
||||
* SL_MEMORY_BLOCK_ALIGN_8_BYTES,
|
||||
* reservation_handle1,
|
||||
* (void **)&ptr8);
|
||||
* if (status != SL_STATUS_OK) {
|
||||
* // Process the error condition.
|
||||
* }
|
||||
*
|
||||
* memset(ptr8, 0xEE, 1024);
|
||||
*
|
||||
* status = sl_memory_release_block(&reservation_handle1);
|
||||
* if (status != SL_STATUS_OK) {
|
||||
* // Process the error condition.
|
||||
* }
|
||||
*
|
||||
* status = sl_memory_reservation_handle_free(reservation_handle1);
|
||||
* if (status != SL_STATUS_OK) {
|
||||
* // Process the error condition.
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* \subsubsection subsubsection-statistics Statistics
|
||||
*
|
||||
* As your code is allocating and freeing blocks, you may want to know at a certain
|
||||
* instant what the current state of the heap is. Some heap statistics queries at
|
||||
* runtime can help to understand the current usage of the heap. By using the
|
||||
* following statistics functions, you may be able to perform some asynchronous
|
||||
* runtime heap checks:
|
||||
* - Total heap size: sl_memory_get_total_heap_size().
|
||||
* - Current free heap size: sl_memory_get_free_heap_size().
|
||||
* - Current used heap size: sl_memory_get_used_heap_size().
|
||||
* - Highest accumulated heap size usage: sl_memory_get_heap_high_watermark().
|
||||
* - You can reset the high heap usage watermark with
|
||||
* sl_memory_reset_heap_high_watermark().
|
||||
*
|
||||
* Besides a few functions each dedicated to a specific statistic, the function
|
||||
* sl_memory_get_heap_info() allows to get a general heap information structure
|
||||
* of type @ref sl_memory_heap_info_t "sl_memory_heap_info_t{}" with several heap
|
||||
* statistics. Some of them overlap the statistics returned by the dedicated
|
||||
* functions while the others complements statistics returned by the dedicated
|
||||
* functions. Refer to the description of @ref sl_memory_heap_info_t
|
||||
* "sl_memory_heap_info_t{}" for more information of each field.
|
||||
*
|
||||
* If you want to know the start address and the total size of the program's
|
||||
* stack and/or heap, simply call respectively the function sl_memory_get_stack_region()
|
||||
* and/or sl_memory_get_heap_region().
|
||||
*
|
||||
* ### C/C++ Toolchains Standard Memory Functions Retarget/Overload
|
||||
*
|
||||
* A program can perform dynamic memory allocations and deallocations using the
|
||||
* standard memory functions whose implementation is provided by the C or C++
|
||||
* toolchain libraries.
|
||||
* - C toolchain for the classic malloc()/free()/calloc()/realloc()
|
||||
* - C++ toolchain for the new/delete operators
|
||||
*
|
||||
* The Memory Manager supports the C standard memory functions retarget and the C++
|
||||
* new/delete overload.
|
||||
*
|
||||
* When the \b memory_manager component is installed, the C standard memory
|
||||
* functions are automatically retargeted to the Memory Manager ones:
|
||||
* - GCC: coupled to the linker option "--wrap", the functions retargeted are
|
||||
* - standard _malloc_r() -> sl_malloc()
|
||||
* - standard _free_r() -> sl_free()
|
||||
* - standard _calloc_r() -> sl_calloc()
|
||||
* - standard _realloc_r() -> sl_realloc()
|
||||
* - IAR: it has three separate heap memory handlers (the basic, the advanced,
|
||||
* and the no-free heap handlers). IAR generally auto-selects one of the handlers.
|
||||
* - Basic heap
|
||||
* - standard __basic_malloc() -> sl_malloc()
|
||||
* - standard __basic_free() -> sl_free()
|
||||
* - standard __basic_calloc() -> sl_calloc()
|
||||
* - standard __basic_realloc() -> sl_realloc()
|
||||
* - Advanced heap
|
||||
* - standard __iar_dl_malloc() -> sl_malloc()
|
||||
* - standard __iar_dl_free() -> sl_free()
|
||||
* - standard __iar_dl_calloc() -> sl_calloc()
|
||||
* - standard __iar_dl_realloc() -> sl_realloc()
|
||||
* - No Free heap
|
||||
* - standard __no_free_malloc() -> sl_malloc()
|
||||
* - standard __no_free_calloc() -> sl_calloc()
|
||||
*
|
||||
* If you need the C++ new/delete global overload calling sl_memory_alloc() and
|
||||
* sl_memory_free(), please install the additional component
|
||||
* \b memory_manager_cpp.
|
||||
* This global overload of new/delete operators will also apply to any C++
|
||||
* standard containers (for example vector, string, list).
|
||||
*
|
||||
* @note The Silicon Labs SDK generates a GCC or IAR linker script with Simplicity
|
||||
* Studio. A typical toolchain linker script will define a section called "heap"
|
||||
* or "HEAP". Usually, the C memory standard functions will assume a linker-defined
|
||||
* "heap" section exists. If the memory_manager component is present, the
|
||||
* toolchain linker script will define a new heap section named "memory_manager_heap"
|
||||
* or "MEMORY_MANAGER_HEAP". Since the Memory Manager retargets the standard
|
||||
* function malloc()/free()/calloc()/realloc() to the Memory Manager ones, there
|
||||
* should not be any issues in your program. If an unlikely situation occurs where
|
||||
* the toolchain standard memory functions retarget does not work, your application
|
||||
* might end up calling a standard malloc() implementation from the
|
||||
* toolchain instead of the Memory Manager one. In that case, a runtime
|
||||
* error can occur and it is expected. You should then review the project settings
|
||||
* to detect why the Memory Manager retarget did not work properly.
|
||||
*
|
||||
* ## Hints
|
||||
* ### Memory Allocations from ISR
|
||||
*
|
||||
* In general, ISR must be kept short. Allocating and freeing blocks from an ISR is
|
||||
* possible but you should be careful. Nothing really prevents you from calling the
|
||||
* dynamic allocation API functions such as sl_malloc() and sl_free(). But keep in
|
||||
* mind a few things with the dynamic allocation API:
|
||||
* - The dynamic allocation API functions protect their internal resources
|
||||
* such as global lists managing the heap metadata by using critical sections.
|
||||
* So when in your ISR, you will disable interrupts for a certain period of time,
|
||||
* preventing other interrupts to be processed in time if your application has hard
|
||||
* real-time constraints. This increases the overall interrupt latency of your
|
||||
* system if this ISR executes very often to perform a dynamic memory operation
|
||||
* - They can introduce non-deterministic behavior which is undesirable if your
|
||||
* application requires crucial precise timing
|
||||
* - A function such as sl_malloc() can fail if there is no block to satisfy
|
||||
* your requested size allocation. Implementing the proper error handling in the
|
||||
* ISR may increase the time spent in the ISR.
|
||||
*
|
||||
* In the end, it really depends of your ISR processing context doing memory
|
||||
* allocations/deallocations. If you really need to perform dynamic allocation from
|
||||
* ISR, it may be better at least to use a memory pool. Getting and releasing a block
|
||||
* from a pool is an operation more deterministic. And if you have properly
|
||||
* sized your pool with a number of available blocks, you are less likely to
|
||||
* encounter an allocation error.
|
||||
*
|
||||
* @{
|
||||
*****************************************************************************/
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// DEFINES
|
||||
|
||||
/// Special value to indicate the default block alignment to the Memory Manager
|
||||
/// allocator. 8 bytes is the minimum alignment to account for largest CPU data
|
||||
/// type that can be used in some block allocation scenarios.
|
||||
#define SL_MEMORY_BLOCK_ALIGN_DEFAULT 0xFFFFFFFFU
|
||||
|
||||
/// Pre-defined values for block alignment managed by the Memory Manager allocator.
|
||||
#define SL_MEMORY_BLOCK_ALIGN_8_BYTES 8U ///< 8 bytes alignment.
|
||||
#define SL_MEMORY_BLOCK_ALIGN_16_BYTES 16U ///< 16 bytes alignment.
|
||||
#define SL_MEMORY_BLOCK_ALIGN_32_BYTES 32U ///< 32 bytes alignment.
|
||||
#define SL_MEMORY_BLOCK_ALIGN_64_BYTES 64U ///< 64 bytes alignment.
|
||||
#define SL_MEMORY_BLOCK_ALIGN_128_BYTES 128U ///< 128 bytes alignment.
|
||||
#define SL_MEMORY_BLOCK_ALIGN_256_BYTES 256U ///< 256 bytes alignment.
|
||||
#define SL_MEMORY_BLOCK_ALIGN_512_BYTES 512U ///< 512 bytes alignment.
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// DATA TYPES
|
||||
|
||||
/// @brief Block type.
|
||||
typedef enum {
|
||||
BLOCK_TYPE_LONG_TERM = 0, ///< Long-term block type.
|
||||
BLOCK_TYPE_SHORT_TERM = 1 ///< Short-term block type.
|
||||
} sl_memory_block_type_t;
|
||||
|
||||
/// @brief General purpose heap information.
|
||||
typedef struct {
|
||||
uint32_t base_addr; ///< Heap base address.
|
||||
size_t used_size; ///< Used size (in bytes), independently of alignment.
|
||||
size_t free_size; ///< Free size (in bytes), independently of alignment.
|
||||
size_t total_size; ///< Total heap size (in bytes).
|
||||
size_t free_block_count; ///< Number of free blocks.
|
||||
size_t free_block_largest_size; ///< Largest free block size (in bytes).
|
||||
size_t free_block_smallest_size; ///< Smallest free block size (in bytes).
|
||||
size_t used_block_count; ///< Number of used blocks.
|
||||
size_t used_block_largest_size; ///< Largest used block size (in bytes).
|
||||
size_t used_block_smallest_size; ///< Smallest used block size (in bytes).
|
||||
} sl_memory_heap_info_t;
|
||||
|
||||
/// @brief Memory block reservation handle.
|
||||
typedef struct {
|
||||
void *block_address; ///< Reserved block base address.
|
||||
size_t block_size; ///< Reserved block size (in bytes).
|
||||
} sl_memory_reservation_t;
|
||||
|
||||
/// @brief Memory pool handle.
|
||||
typedef struct {
|
||||
#if defined(SL_MEMORY_POOL_POWER_AWARE)
|
||||
sl_memory_reservation_t *reservation; ///< Pointer to reservation handle.
|
||||
#else
|
||||
void *block_address; ///< Reserved block base address.
|
||||
#endif
|
||||
uint32_t *block_free; ///< Pointer to pool's free blocks list.
|
||||
size_t block_count; ///< Max quantity of blocks in the pool.
|
||||
size_t block_size; ///< Size of each block.
|
||||
} sl_memory_pool_t;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// PROTOTYPES
|
||||
|
||||
/***************************************************************************//**
|
||||
* Initializes the memory manager.
|
||||
*
|
||||
* @return SL_STATUS_OK if successful. Error code otherwise.
|
||||
*
|
||||
* @note This function should only be called once.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_memory_init(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Reserves a memory block that will never need retention in EM2.
|
||||
*
|
||||
* @param[in] size Size of the block, in bytes.
|
||||
* @param[in] align Required alignment for the block, in bytes.
|
||||
* @param[out] block Pointer to variable that will receive the start address
|
||||
* of the allocated block. NULL in case of error condition.
|
||||
*
|
||||
* @return SL_STATUS_OK if successful. Error code otherwise.
|
||||
*
|
||||
* @note Required alignment of memory block (in bytes) MUST be a power of 2
|
||||
* and can range from 1 to 512 bytes.
|
||||
* The define SL_MEMORY_BLOCK_ALIGN_DEFAULT can be specified to select
|
||||
* the default alignment.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_memory_reserve_no_retention(size_t size,
|
||||
size_t align,
|
||||
void **block);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Allocates a memory block of at least requested size from the heap. Simple
|
||||
* version.
|
||||
*
|
||||
* @param[in] size Size of the block, in bytes.
|
||||
*
|
||||
* @return Pointer to allocated block if successful. Null pointer if
|
||||
* allocation failed.
|
||||
*
|
||||
* @note Requesting a block of 0 byte will return a null pointer.
|
||||
*
|
||||
* @note All allocated blocks using this function will be considered long-term
|
||||
* allocations.
|
||||
******************************************************************************/
|
||||
void *sl_malloc(size_t size);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Dynamically allocates a block of memory.
|
||||
*
|
||||
* @param[in] size Size of the block, in bytes.
|
||||
* @param[in] type Type of block (long-term or short-term).
|
||||
* BLOCK_TYPE_LONG_TERM
|
||||
* BLOCK_TYPE_SHORT_TERM
|
||||
* @param[out] block Pointer to variable that will receive the start address
|
||||
* of the allocated block. NULL in case of error condition.
|
||||
*
|
||||
* @return SL_STATUS_OK if successful. Error code otherwise.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_memory_alloc(size_t size,
|
||||
sl_memory_block_type_t type,
|
||||
void **block);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Dynamically allocates a block of memory. Advanced version that allows to
|
||||
* specify alignment.
|
||||
*
|
||||
* @param[in] size Size of the block, in bytes.
|
||||
* @param[in] align Required alignment for the block, in bytes.
|
||||
* @param[in] type Type of block (long-term or short term).
|
||||
* BLOCK_TYPE_LONG_TERM
|
||||
* BLOCK_TYPE_SHORT_TERM
|
||||
* @param[out] block Pointer to variable that will receive the start address
|
||||
* of the allocated block. NULL in case of error condition.
|
||||
*
|
||||
* @return SL_STATUS_OK if successful. Error code otherwise.
|
||||
*
|
||||
* @note Required alignment of memory block (in bytes) MUST be a power of 2
|
||||
* and can range from 1 to 512 bytes.
|
||||
* The define SL_MEMORY_BLOCK_ALIGN_DEFAULT can be specified to select
|
||||
* the default alignment.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_memory_alloc_advanced(size_t size,
|
||||
size_t align,
|
||||
sl_memory_block_type_t type,
|
||||
void **block);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Frees a previously allocated block back into the heap. Simple version.
|
||||
*
|
||||
* @param[in] ptr Pointer to memory block to be freed.
|
||||
*
|
||||
* @note Passing a null pointer does nothing.
|
||||
******************************************************************************/
|
||||
void sl_free(void *ptr);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Frees a dynamically allocated block of memory.
|
||||
*
|
||||
* @param[in] block Pointer to the block that must be freed.
|
||||
*
|
||||
* @return SL_STATUS_OK if successful. Error code otherwise.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_memory_free(void *block);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Dynamically allocates a block of memory cleared to 0. Simple version.
|
||||
*
|
||||
* @param[in] item_count Number of elements to be allocated.
|
||||
* @param[in] size Size of each elements, in bytes.
|
||||
*
|
||||
* @return Pointer to allocated block if successful. Null pointer if
|
||||
* allocation failed.
|
||||
*
|
||||
* @note All allocated blocks using this function will be considered long-term
|
||||
* allocations.
|
||||
******************************************************************************/
|
||||
void *sl_calloc(size_t item_count,
|
||||
size_t size);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Dynamically allocates a block of memory cleared to 0.
|
||||
*
|
||||
* @param[in] item_count Number of elements to be allocated.
|
||||
* @param[in] size Size of each elements, in bytes.
|
||||
* @param[in] type Type of block (long-term or short-term).
|
||||
* BLOCK_TYPE_LONG_TERM
|
||||
* BLOCK_TYPE_SHORT_TERM
|
||||
* @param[out] block Pointer to variable that will receive the start
|
||||
* address of the allocated block. NULL in case of
|
||||
* error condition.
|
||||
*
|
||||
* @return SL_STATUS_OK if successful. Error code otherwise.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_memory_calloc(size_t item_count,
|
||||
size_t size,
|
||||
sl_memory_block_type_t type,
|
||||
void **block);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Resizes a previously allocated memory block. Simple version.
|
||||
*
|
||||
* @param[in] ptr Pointer to the allocation to resize. If NULL, behavior
|
||||
* is same as sl_malloc(), sl_memory_alloc().
|
||||
* @param[in] size New size of the block, in bytes. If 0, behavior is same as
|
||||
* sl_free(), sl_memory_free().
|
||||
*
|
||||
* @return Pointer to newly allocated block, if successful. Null pointer if
|
||||
* re-allocation failed.
|
||||
*
|
||||
* @note All re-allocated blocks using this function will be considered
|
||||
* long-term allocations.
|
||||
*
|
||||
* @note 'ptr' NULL and 'size' of 0 bytes is an incorrect parameters
|
||||
* combination. No reallocation will be done by the function as it is
|
||||
* an error condition.
|
||||
*
|
||||
* @note If the new 'size' is the same as the old, the function changes nothing
|
||||
* and returns the same provided address 'ptr'.
|
||||
******************************************************************************/
|
||||
void *sl_realloc(void *ptr,
|
||||
size_t size);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Resizes a previously allocated memory block.
|
||||
*
|
||||
* @param[in] ptr Pointer to the allocation to resize. If NULL, behavior
|
||||
* is same as sl_malloc(), sl_memory_alloc().
|
||||
* @param[in] size New size of the block, in bytes. If 0, behavior is same as
|
||||
* sl_free(), sl_memory_free().
|
||||
* @param[out] block Pointer to variable that will receive the start address of
|
||||
* the new allocated memory. NULL in case of error condition.
|
||||
*
|
||||
* @return SL_STATUS_OK if successful. Error code otherwise.
|
||||
*
|
||||
* @note All re-allocated blocks using this function will be considered
|
||||
* long-term allocations.
|
||||
*
|
||||
* @note 'ptr' NULL and 'size' of 0 bytes is an incorrect parameters
|
||||
* combination. No reallocation will be done by the function as it is
|
||||
* an error condition.
|
||||
*
|
||||
* @note If the new 'size' is the same as the old, the function changes nothing
|
||||
* and returns the same provided address 'ptr'.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_memory_realloc(void *ptr,
|
||||
size_t size,
|
||||
void **block);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Dynamically reserves a block of memory.
|
||||
*
|
||||
* @param[in] size Size of the block, in bytes.
|
||||
* @param[in] align Required alignment for the block, in bytes.
|
||||
* @param[in] handle Handle to the reserved block.
|
||||
* @param[out] block Pointer to variable that will receive the start address
|
||||
* of the allocated block. NULL in case of error condition.
|
||||
*
|
||||
* @return SL_STATUS_OK if successful. Error code otherwise.
|
||||
*
|
||||
* @note Required alignment of memory block (in bytes) MUST be a power of 2
|
||||
* and can range from 1 to 512 bytes.
|
||||
* The define SL_MEMORY_BLOCK_ALIGN_DEFAULT can be specified to select
|
||||
* the default alignment.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_memory_reserve_block(size_t size,
|
||||
size_t align,
|
||||
sl_memory_reservation_t *handle,
|
||||
void **block);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Frees a dynamically reserved block of memory.
|
||||
*
|
||||
* @param[in] handle Handle to the reserved block.
|
||||
*
|
||||
* @return SL_STATUS_OK if successful. Error code otherwise.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_memory_release_block(sl_memory_reservation_t *handle);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Dynamically allocates a block reservation handle.
|
||||
*
|
||||
* @param[out] handle Handle to the reserved block.
|
||||
*
|
||||
* @return SL_STATUS_OK if successful. Error code otherwise.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_memory_reservation_handle_alloc(sl_memory_reservation_t **handle);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Frees a dynamically allocated block reservation handle.
|
||||
*
|
||||
* @param[in] handle Handle to the reserved block.
|
||||
*
|
||||
* @return SL_STATUS_OK if successful. Error code otherwise.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_memory_reservation_handle_free(sl_memory_reservation_t *handle);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets the size of the memory reservation handle structure.
|
||||
*
|
||||
* @return Memory reservation handle structure's size in bytes.
|
||||
******************************************************************************/
|
||||
uint32_t sl_memory_reservation_handle_get_size(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Creates a memory pool.
|
||||
*
|
||||
* @param[in] block_size Size of each block, in bytes.
|
||||
* @param[in] block_count Number of blocks in the pool.
|
||||
* @param[in] pool_handle Handle to the memory pool.
|
||||
*
|
||||
* @note This function assumes the 'pool_handle' is provided by the caller:
|
||||
* - either statically (e.g. as a global variable)
|
||||
* - or dynamically by calling sl_memory_pool_handle_alloc().
|
||||
*
|
||||
* @return SL_STATUS_OK if successful. Error code otherwise.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_memory_create_pool(size_t block_size,
|
||||
uint32_t block_count,
|
||||
sl_memory_pool_t *pool_handle);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Deletes a memory pool.
|
||||
*
|
||||
* @param[in] pool_handle Handle to the memory pool.
|
||||
*
|
||||
* @return SL_STATUS_OK if successful. Error code otherwise.
|
||||
*
|
||||
* @note All pool allocations need to be freed by calling sl_memory_pool_free()
|
||||
* on each block before calling sl_memory_delete_pool().
|
||||
*
|
||||
* @note The pool_handle provided is neither freed or invalidated. It can be
|
||||
* reused in a new call to sl_memory_create_pool() to create another pool.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_memory_delete_pool(sl_memory_pool_t *pool_handle);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Allocates a block from a memory pool.
|
||||
*
|
||||
* @param[in] pool_handle Handle to the memory pool.
|
||||
* @param[out] block Pointer to a variable that will receive the address
|
||||
* of the allocated block. NULL in case of error
|
||||
* condition.
|
||||
*
|
||||
* @return SL_STATUS_OK if successful. Error code otherwise.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_memory_pool_alloc(sl_memory_pool_t *pool_handle,
|
||||
void **block);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Frees a block from a memory pool.
|
||||
*
|
||||
* @param[in] pool_handle Handle to the memory pool.
|
||||
* @param[in] block Pointer to the block to free.
|
||||
*
|
||||
* @return SL_STATUS_OK if successful. Error code otherwise.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_memory_pool_free(sl_memory_pool_t *pool_handle,
|
||||
void *block);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Dynamically allocates a memory pool handle.
|
||||
*
|
||||
* @param[out] pool_handle Handle to the memory pool.
|
||||
*
|
||||
* @return SL_STATUS_OK if successful. Error code otherwise.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_memory_pool_handle_alloc(sl_memory_pool_t **pool_handle);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Frees a dynamically allocated memory pool handle.
|
||||
*
|
||||
* @param[in] pool_handle Handle to the memory pool.
|
||||
*
|
||||
* @return SL_STATUS_OK if successful. Error code otherwise.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_memory_pool_handle_free(sl_memory_pool_t *pool_handle);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets the size of the memory pool handle structure.
|
||||
*
|
||||
* @return Memory pool handle structure's size.
|
||||
******************************************************************************/
|
||||
uint32_t sl_memory_pool_handle_get_size(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets the total count of blocks in a memory pool.
|
||||
*
|
||||
* @param[in] pool_handle Handle to the memory pool.
|
||||
*
|
||||
* @return Total number of blocks.
|
||||
******************************************************************************/
|
||||
uint32_t sl_memory_pool_get_total_block_count(const sl_memory_pool_t *pool_handle);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets the count of free blocks in a memory pool.
|
||||
*
|
||||
* @param[in] pool_handle Handle to the memory pool.
|
||||
*
|
||||
* @return Number of free blocks.
|
||||
******************************************************************************/
|
||||
uint32_t sl_memory_pool_get_free_block_count(const sl_memory_pool_t *pool_handle);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets the count of used blocks in a memory pool.
|
||||
*
|
||||
* @param[in] pool_handle Handle to the memory pool.
|
||||
*
|
||||
* @return Number of used blocks.
|
||||
******************************************************************************/
|
||||
uint32_t sl_memory_pool_get_used_block_count(const sl_memory_pool_t *pool_handle);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Populates an sl_memory_heap_info_t{} structure with the current status of
|
||||
* the heap.
|
||||
*
|
||||
* @param[in] heap_info Pointer to structure that will receive further heap
|
||||
* information data.
|
||||
*
|
||||
* @return SL_STATUS_OK if successful. Error code otherwise.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_memory_get_heap_info(sl_memory_heap_info_t *heap_info);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets the total size of the heap.
|
||||
*
|
||||
* @return Heap's size in bytes.
|
||||
******************************************************************************/
|
||||
size_t sl_memory_get_total_heap_size(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets the current free heap size.
|
||||
*
|
||||
* @return Free heap size in bytes.
|
||||
******************************************************************************/
|
||||
size_t sl_memory_get_free_heap_size(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets the current used heap size.
|
||||
*
|
||||
* @return Used heap size in bytes.
|
||||
******************************************************************************/
|
||||
size_t sl_memory_get_used_heap_size(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets heap high watermark.
|
||||
*
|
||||
* @return Highest heap usage in bytes recorded.
|
||||
******************************************************************************/
|
||||
size_t sl_memory_get_heap_high_watermark(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Reset heap high watermark to the current heap used.
|
||||
******************************************************************************/
|
||||
void sl_memory_reset_heap_high_watermark(void);
|
||||
|
||||
/** @} (end addtogroup memory_manager) */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SL_MEMORY_MANAGER_H_ */
|
||||
@@ -0,0 +1,77 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief Getters for Heap and stack.
|
||||
*******************************************************************************
|
||||
* # 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.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef SL_MEMORY_MANAGER_REGION_H_
|
||||
#define SL_MEMORY_MANAGER_REGION_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/***************************************************************************//**
|
||||
* @addtogroup memory_manager Memory Manager
|
||||
* @{
|
||||
******************************************************************************/
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// DATA TYPES
|
||||
|
||||
/// @brief Memory region structure.
|
||||
typedef struct sl_memory_region_t {
|
||||
void * addr; ///< Pointer to the beginning of the memory region. Can be NULL.
|
||||
size_t size; ///< Size of this memory region.
|
||||
} sl_memory_region_t;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// PROTOTYPES
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets size and location of the stack.
|
||||
*
|
||||
* @return description of the region reserved for the C stack.
|
||||
******************************************************************************/
|
||||
sl_memory_region_t sl_memory_get_stack_region(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets size and location of the heap.
|
||||
*
|
||||
* @return description of the region reserved for the C heap.
|
||||
******************************************************************************/
|
||||
sl_memory_region_t sl_memory_get_heap_region(void);
|
||||
|
||||
/** @} end addtogroup memory_manager) */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SL_MEMORY_MANAGER_REGION_H_ */
|
||||
@@ -0,0 +1,631 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief Macros and functions for memory profiling
|
||||
*******************************************************************************
|
||||
* # License
|
||||
* <b>Copyright 2023 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_MEMORY_PROFILER_H
|
||||
#define SLI_MEMORY_PROFILER_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "sl_status.h"
|
||||
|
||||
#if defined(SL_COMPONENT_CATALOG_PRESENT)
|
||||
|
||||
// The component catalog is present, so we're in an application build and can
|
||||
// check if the Memory Profiler is present
|
||||
#include "sl_component_catalog.h"
|
||||
#if defined(SL_CATALOG_MEMORY_PROFILER_PRESENT)
|
||||
// The Memory Profiler is present. Use its configuration and enable profiling.
|
||||
#include "sli_memory_profiler_config.h"
|
||||
#define SLI_MEMORY_PROFILER_ENABLE_PROFILING 1
|
||||
#else
|
||||
// The Memory Profiler is not present. Disable profiling.
|
||||
#define SLI_MEMORY_PROFILER_ENABLE_PROFILING 0
|
||||
#endif // defined(SL_CATALOG_MEMORY_PROFILER_PRESENT)
|
||||
|
||||
#else // defined(SL_COMPONENT_CATALOG_PRESENT)
|
||||
|
||||
// The component catalog is not present, so we're in a library build. The build
|
||||
// environment of the library must specify the configuration defines that affect
|
||||
// the macros in this header if it wants a non-default configuration. We default
|
||||
// to enabling basic profiling but disabling ownership tracking.
|
||||
#if !defined(SLI_MEMORY_PROFILER_ENABLE_PROFILING)
|
||||
#define SLI_MEMORY_PROFILER_ENABLE_PROFILING 1
|
||||
#endif
|
||||
|
||||
#if !defined(SLI_MEMORY_PROFILER_ENABLE_OWNERSHIP_TRACKING)
|
||||
#define SLI_MEMORY_PROFILER_ENABLE_OWNERSHIP_TRACKING 0
|
||||
#endif
|
||||
|
||||
#endif // defined(SL_COMPONENT_CATALOG_PRESENT)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/// @cond DO_NOT_INCLUDE_WITH_DOXYGEN
|
||||
/***************************************************************************//**
|
||||
* @addtogroup memory_profiler Memory Profiler
|
||||
* @{
|
||||
*
|
||||
* @brief Memory profiler for tracking and reporting system RAM usage
|
||||
*
|
||||
* This memory profiler component provides a tool for tracking and reporting of
|
||||
* system RAM usage. It is implemented as a combination of a simple component
|
||||
* running in the Device Under Test (DUT) and a Python script running on a
|
||||
* computer. The on-DUT component is a relatively thin layer that uses J-Link
|
||||
* RTT (Real Time Transfer) to output events about memory allocation on the
|
||||
* device. The Python script on the computer receives these events and maintains
|
||||
* the memory usage bookkeeping. The script is available in
|
||||
* `platform/service/memory_manager/profiler/scripts/memory_profiler_platform.py`.
|
||||
*
|
||||
* The memory profiler represents memory in a hierarchical structure with the
|
||||
* physical RAM as the root of the tree. The physical RAM is split into
|
||||
* allocations such as stack and heap, and the heap is further split into
|
||||
* allocations for different uses of memory.
|
||||
*
|
||||
* Each node in the tree is represented by one instance of a memory tracker.
|
||||
* Each tracker has a short description and records the current and peak number
|
||||
* of bytes allocated. Leaves in the tree represent concrete uses of RAM, for
|
||||
* example allocations of a particular object types in a wireless stack.
|
||||
* Intermediate nodes typically correspond to memory allocation abstractions,
|
||||
* such as memory pools or helper functions that are used by the concrete users
|
||||
* of memory.
|
||||
*
|
||||
* The trackers can represent two different types of allocation behavior:
|
||||
*
|
||||
* 1. Pool trackers represent memory abstractions that make one contiguous
|
||||
* allocation from their parent memory to allocate a pool. Portions of that
|
||||
* pool are then given to callers that allocate memory from the pool
|
||||
* abstraction. The Memory Manager (MM) heap is one example of such a
|
||||
* pool. The MM heap reserves some portion of the physical RAM at
|
||||
* initialization time and gives portions of that pool to its callers.
|
||||
* Another example of a pool tracker are the individual pools that can be
|
||||
* created and deleted at runtime using the MM Pool API. Each pool is
|
||||
* associated with a pool tracker to track the allocation and freeing of the
|
||||
* pool items during the lifetime of the pool.
|
||||
*
|
||||
* 2. Trackers that are not pools are used to collect the allocation statistics
|
||||
* of a certain type of allocation or use case so that the memory use of that
|
||||
* particular type can be easily distinguished from all the other users of
|
||||
* memory. For example, the Memory Manager creates a separate tracker
|
||||
* for long-term heap allocations, short-term heap allocations, and heap
|
||||
* reservations, so that these can be counted individually. Components such
|
||||
* as wireless stacks may create their own trackers for tracking things like
|
||||
* the total sum of allocations made by a particular component, or more
|
||||
* granularly the allocations made for a particular type of a resource.
|
||||
*
|
||||
* The Memory Manager is integrated to the Memory Profiler and all
|
||||
* allocations from the heap are automatically tracked by the top-level trackers
|
||||
* for the heap. This provides the usage tracking for the heap as a whole, i.e.
|
||||
* how many bytes of heap are used in total. If a component or an application
|
||||
* wants to track how many bytes it has allocated from the heap, it can create a
|
||||
* new memory profiler tracker. Pool memory trackers are created with a call to
|
||||
* `sli_memory_profiler_create_pool_tracker()` and other trackers are created
|
||||
* with `sli_memory_profiler_create_tracker()`.
|
||||
*
|
||||
* Both types of trackers are identified by a handle of type
|
||||
* `sli_memory_tracker_handle_t`, which is just a void pointer that is provided
|
||||
* by the code that creates the tracker. Code that creates a tracker can use any
|
||||
* void pointer that is guaranteed to be unique among all trackers for the
|
||||
* duration of the tracker lifetime, i.e. until the tracker is deleted with a
|
||||
* call to `sli_memory_profiler_delete_tracker()`. A good approach is to use a
|
||||
* pointer that is tightly associated with the tracked object or use case. For
|
||||
* example, a tracker for a memory pool can use the pool handle as the tracker
|
||||
* handle. A function that wants to track the allocations it makes can use its
|
||||
* own function pointer as the tracker handle.
|
||||
*
|
||||
* Top-level trackers for the heap are created at platform initialization time
|
||||
* and are never deleted. Other trackers have the same lifetime as the entity or
|
||||
* component that is being tracked. For example, when a memory pool is created,
|
||||
* a tracker is created for the pool. When the pool is deleted, the tracker is
|
||||
* also deleted. Similarly if a component creates a tracker for its memory use
|
||||
* when the component is initialized or started, the component would typically
|
||||
* delete the tracker for its memory when the component is de-initialized or
|
||||
* stopped. Trackers are deleted with a call to
|
||||
* `sli_memory_profiler_delete_tracker()`.
|
||||
*
|
||||
* The memory profiler implementation aims to minimize the impact of the memory
|
||||
* profiler calls on both RAM and CPU usage when the profiling is not enabled by
|
||||
* including the component in the SW configuration. To keep the calling code
|
||||
* clean of conditional compilation but still allow completely removing the
|
||||
* tracking calls when the profiler is not used, the calling code is encouraged
|
||||
* to do the tracking via the macros such as @ref
|
||||
* SLI_MEMORY_PROFILER_TRACK_ALLOC() and @ref SLI_MEMORY_PROFILER_TRACK_FREE().
|
||||
* These macros will automatically expand to empty when the profiling is
|
||||
* disabled at build time.
|
||||
*
|
||||
* If a component is compiled into a library (as opposed to being compiled at
|
||||
* application build time), the library may contain calls to the Memory Profiler
|
||||
* API even if tracking will be disabled in the application. In this case the SW
|
||||
* is linked with a stub Memory Profiler API implementation that provides dummy
|
||||
* functions. The stub implementation does not use any RAM or RTT, so the
|
||||
* overhead is minimized.
|
||||
*
|
||||
* Trackers use @ref SLI_MEMORY_PROFILER_TRACK_ALLOC() to track the allocation of
|
||||
* memory blocks and include the bytes of RAM to the counts in the trackers. To
|
||||
* make sure that any arbitrary pointer can be correctly mapped to the
|
||||
* allocation it belongs to, every tracker must accurately track the pointer and
|
||||
* size of the memory block that they are operating with. As an example, when an
|
||||
* allocation from the MM heap is made, the MM heap implementation tracks the
|
||||
* full allocation RAM block including any extra metadata or size padding that
|
||||
* is used around the block returned to the caller. The caller will track the
|
||||
* allocation using the size it requested from the heap (which is smaller than
|
||||
* the full block needed to satisfy the allocation), and the pointer it received
|
||||
* from the heap (which is within the full block allocated from the RAM).
|
||||
*
|
||||
* Trackers use @ref SLI_MEMORY_PROFILER_TRACK_FREE() to mark the freeing of a
|
||||
* memory block. Here too the callers must accurately identify the freed block
|
||||
* by providing the same pointer they provided in the corresponding call to
|
||||
* track the allocation. The tracking of the free does not need to be fully
|
||||
* symmetric, though. As an example, assume that an app has created the tracker
|
||||
* `app_mallocs` and is using @ref SLI_MEMORY_PROFILER_TRACK_ALLOC() to track on
|
||||
* that tracker every block it received from @ref sl_malloc(). When the
|
||||
* application calls @ef sl_free() to free a memory block, the application does
|
||||
* not need to call @ref SLI_MEMORY_PROFILER_TRACK_FREE() to mark the freeing.
|
||||
* The MM heap will track the freeing in `sl_free()` and the freeing of the
|
||||
* memory is automatically counted in the `app_mallocs` tracker as well.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief Memory tracker handle type
|
||||
*/
|
||||
typedef const void* sli_memory_tracker_handle_t;
|
||||
|
||||
/**
|
||||
* @brief Value used to indicate an invalid memory tracker handle
|
||||
*/
|
||||
#define SLI_INVALID_MEMORY_TRACKER_HANDLE ((sli_memory_tracker_handle_t) NULL)
|
||||
|
||||
/**
|
||||
* @brief Initialize the memory profiler
|
||||
*
|
||||
* Memory Profiler initialization is handled internally by the Platform
|
||||
* initialization. Applications do not need to and should not call this function
|
||||
* directly.
|
||||
*/
|
||||
void sli_memory_profiler_init();
|
||||
|
||||
/**
|
||||
* @brief Get the current program counter
|
||||
*
|
||||
* This helper can be used to obtain the current program counter when invoking
|
||||
* @ref SLI_MEMORY_PROFILER_TRACK_OWNERSHIP() with the intention of assigning
|
||||
* the ownership to the location that is invoking the tracking macro.
|
||||
*
|
||||
* @return Current program counter
|
||||
*/
|
||||
#if defined(__GNUC__)
|
||||
__attribute__( (always_inline) ) static inline void * sli_memory_profiler_get_pc(void)
|
||||
{
|
||||
void *pc;
|
||||
__asm volatile ("MOV %0, PC" : "=r" (pc));
|
||||
return pc;
|
||||
}
|
||||
#elif defined(__IAR_SYSTEMS_ICC__)
|
||||
_Pragma("inline=forced") static inline void * sli_memory_profiler_get_pc(void)
|
||||
{
|
||||
void *pc;
|
||||
__asm volatile ("MOV %0, PC" : "=r" (pc));
|
||||
return pc;
|
||||
}
|
||||
#else
|
||||
static inline void * sli_memory_profiler_get_pc(void)
|
||||
{
|
||||
// Memory Profiler supports ownership tracking only with the GCC or IAR compiler
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Get the return address of the current function
|
||||
*
|
||||
* This helper can be used to obtain the return address of the current function
|
||||
* when invoking @ref SLI_MEMORY_PROFILER_TRACK_OWNERSHIP() with the intention
|
||||
* of assigning the ownership to the location that made the call to the function
|
||||
* that is invoking the tracking macro.
|
||||
*
|
||||
* Note that the IAR compiler does not provide a mechanism to reliably obtain
|
||||
* the return address, so we must emulate that by taking the content of the link
|
||||
* register. This is never completely reliable, but is guaranteed to fail if
|
||||
* `sli_memory_profiler_get_return_address()` is used in a function after calls
|
||||
* to other functions have already been made. Therefore this function should
|
||||
* always be called right at the beginning of the function that wants to know
|
||||
* the return address.
|
||||
*
|
||||
* @return The return address of the current function
|
||||
*/
|
||||
#if defined(__GNUC__)
|
||||
__attribute__( (always_inline) ) static inline void * sli_memory_profiler_get_return_address(void)
|
||||
{
|
||||
return __builtin_extract_return_addr(__builtin_return_address(0));
|
||||
}
|
||||
#elif defined(__IAR_SYSTEMS_ICC__)
|
||||
_Pragma("inline=forced") static inline void * sli_memory_profiler_get_return_address(void)
|
||||
{
|
||||
uint32_t lr;
|
||||
lr = __get_LR();
|
||||
return (void *)lr;
|
||||
}
|
||||
#else
|
||||
static inline void * sli_memory_profiler_get_return_address(void)
|
||||
{
|
||||
// Memory Profiler supports ownership tracking only with the GCC or IAR compiler
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Create a pool memory tracker
|
||||
*
|
||||
* This function creates a memory tracker for a memory use case that allocates
|
||||
* one fixed-size pool from some allocator and then allocates portions of the
|
||||
* pool to its own clients.
|
||||
*
|
||||
* The memory block specified by @p pointer and @p size must match a memory
|
||||
* allocation that the pool implementation has successfully obtained from some
|
||||
* memory allocator that has tracked the allocation. If the pool implementation
|
||||
* later frees the pool memory block (for example when the component that uses
|
||||
* the pool is de-initialized), the pool implementation must delete the pool
|
||||
* tracker with a call to @ref sli_memory_profiler_delete_tracker before it
|
||||
* frees the memory block that the pool was using.
|
||||
*
|
||||
* @param[in] tracker_handle The handle to identify the tracker. The handle must
|
||||
* remain unique among all trackers until the tracker is deleted with @ref
|
||||
* sli_memory_profiler_delete_tracker.
|
||||
* @param[in] description Short description of the usage of the tracker memory,
|
||||
* or NULL to omit the description. The description can be set or updated
|
||||
* later with a call to @ref sli_memory_profiler_describe_tracker.
|
||||
* @param[in] ptr Pointer to the pool block allocated from the parent memory
|
||||
* @param[in] size The size of the pool block allocated from the parent memory
|
||||
*
|
||||
* @return SL_STATUS_OK if a tracker was created, SL_STATUS_NOT_AVAILABLE if the
|
||||
* Memory Profiler is not included in the application.
|
||||
*/
|
||||
sl_status_t sli_memory_profiler_create_pool_tracker(sli_memory_tracker_handle_t tracker_handle,
|
||||
const char *description,
|
||||
void* ptr,
|
||||
size_t size);
|
||||
|
||||
/**
|
||||
* @brief Create a memory tracker
|
||||
*
|
||||
* This function creates a memory tracker for a use case that allocates blocks
|
||||
* from tracked parent allocator.
|
||||
*
|
||||
* @param[in] tracker_handle The handle to identify the tracker. The handle must
|
||||
* remain unique among all trackers until the tracker is deleted with @ref
|
||||
* sli_memory_profiler_delete_tracker.
|
||||
* @param[in] description Short description of the usage of the tracker memory,
|
||||
* or NULL to omit the description. The description can be set or updated
|
||||
* later with a call to @ref sli_memory_profiler_describe_tracker.
|
||||
*
|
||||
* @return SL_STATUS_OK if a tracker was created, SL_STATUS_NOT_AVAILABLE if the
|
||||
* Memory Profiler is not included in the application.
|
||||
*/
|
||||
sl_status_t sli_memory_profiler_create_tracker(sli_memory_tracker_handle_t tracker_handle,
|
||||
const char *description);
|
||||
|
||||
/**
|
||||
* @brief Add or update a description to a previously created memory tracker
|
||||
*
|
||||
* This function is typically used to assign a description to a tracker that has
|
||||
* been created by a lower layer that does not know the use case of the memory.
|
||||
* For example, when the Memory Manager creates a memory pool object, it
|
||||
* creates a Memory Profiler tracker with the same handle as the pool handle but
|
||||
* cannot assign a descriptive name, as it cannot know what the pool is used
|
||||
* for. The caller that created the pool can then use this function with the
|
||||
* pool handle to assign a description for the pool memory.
|
||||
*
|
||||
* @param[in] tracker_handle The handle of the memory tracker
|
||||
* @param[in] description Short description of the usage of the tracker memory,
|
||||
* or NULL to clear the description.
|
||||
*/
|
||||
void sli_memory_profiler_describe_tracker(sli_memory_tracker_handle_t tracker_handle,
|
||||
const char *description);
|
||||
|
||||
/**
|
||||
* @brief Delete a memory tracker
|
||||
*
|
||||
* This function deletes a previously created memory tracker.
|
||||
*
|
||||
* @param[in] tracker_handle The handle of the memory tracker
|
||||
*/
|
||||
void sli_memory_profiler_delete_tracker(sli_memory_tracker_handle_t tracker_handle);
|
||||
|
||||
/**
|
||||
* @brief Track the allocation of a memory block
|
||||
*
|
||||
* NOTE: This function is intended to be called via the @ref
|
||||
* SLI_MEMORY_PROFILER_TRACK_ALLOC() macro.
|
||||
*
|
||||
* @param[in] tracker_handle The handle of the memory tracker
|
||||
* @param[in] ptr Pointer to the allocated memory or NULL if allocation failed
|
||||
* @param[in] size The number of bytes allocated, or attempted to allocate
|
||||
*/
|
||||
void sli_memory_profiler_track_alloc(sli_memory_tracker_handle_t tracker_handle,
|
||||
void * ptr,
|
||||
size_t size);
|
||||
|
||||
/**
|
||||
* @brief Track the reallocation of a previously allocated memory block
|
||||
*
|
||||
* NOTE: This function is intended to be called via the @ref
|
||||
* SLI_MEMORY_PROFILER_TRACK_REALLOC() macro.
|
||||
*
|
||||
* NOTE: Reallocation is a special operation that is intended to be tracked only
|
||||
* by the underlying heap allocator in the Memory Manager. Any
|
||||
* higher-level allocations that are tracked within the reallocated block are
|
||||
* automatically moved and resized without any tracking calls from the
|
||||
* higher-level trackers.
|
||||
*
|
||||
* If the realloc operation involves allocating a new block and freeing the
|
||||
* previous block, the Memory Manager heap must track the realloc when
|
||||
* the allocation of the new memory has been tracked but the old memory block
|
||||
* has not been freed yet. This is needed to guarantee that both @p ptr and @p
|
||||
* realloced_ptr are valid and owned by the calling thread when the realloc is
|
||||
* tracked.
|
||||
*
|
||||
* @param[in] tracker_handle The handle of the lowest-layer heap memory tracker
|
||||
* @param[in] ptr Pointer to the original memory block
|
||||
* @param[in] realloced_ptr Pointer to the resized or allocated memory
|
||||
* @param[in] size The size that the block was reallocated to
|
||||
*/
|
||||
void sli_memory_profiler_track_realloc(sli_memory_tracker_handle_t tracker_handle,
|
||||
void * ptr,
|
||||
void * realloced_ptr,
|
||||
size_t size);
|
||||
|
||||
/**
|
||||
* @brief Track the allocation of a memory block and record ownership
|
||||
*
|
||||
* NOTE: This function is intended to be called via the @ref
|
||||
* SLI_MEMORY_PROFILER_TRACK_ALLOC_WITH_OWNERSHIP() macro.
|
||||
*
|
||||
* @param[in] tracker_handle The handle of the memory tracker
|
||||
* @param[in] ptr Pointer to the allocated memory or NULL if allocation failed
|
||||
* @param[in] size The number of bytes allocated, or attempted to allocate
|
||||
* @param[in] pc The program counter at the location of the allocation
|
||||
*/
|
||||
void sli_memory_profiler_track_alloc_with_ownership(sli_memory_tracker_handle_t tracker_handle,
|
||||
void * ptr,
|
||||
size_t size,
|
||||
void * pc);
|
||||
|
||||
/**
|
||||
* @brief Track the freeing of a memory block
|
||||
*
|
||||
* NOTE: This function is intended to be called via the
|
||||
* @ref SLI_MEMORY_PROFILER_TRACK_FREE() macro.
|
||||
*
|
||||
* @param[in] tracker_handle The handle of the memory tracker
|
||||
* @param[in] ptr Pointer to the allocated memory
|
||||
*/
|
||||
void sli_memory_profiler_track_free(sli_memory_tracker_handle_t tracker_handle,
|
||||
void * ptr);
|
||||
|
||||
/**
|
||||
* @brief Track the transfer of memory allocation ownership
|
||||
*
|
||||
* NOTE: This function is intended to be called via @ref
|
||||
* SLI_MEMORY_PROFILER_TRACK_OWNERSHIP() or @ref
|
||||
* SLI_MEMORY_PROFILER_TRACK_OWNERSHIP_ON_TRACKER() macros.
|
||||
*
|
||||
* @param[in] tracker_handle Handle of the tracker level at which the ownership
|
||||
* is taken. This is used to disambiguate in cases where nested allocations
|
||||
* start at the same memory location, and the caller is specifically taking
|
||||
* ownership of one of the outer blocks that may contain smaller allocations
|
||||
* that have their own (more detailed) owners. If set to
|
||||
* `SLI_INVALID_MEMORY_TRACKER_HANDLE`, the ownership of the innermost
|
||||
* allocation is taken.
|
||||
* @param[in] ptr Pointer to the allocated memory for which ownership is taken.
|
||||
* The caller may pass a NULL pointer to indicate that the location pointer to
|
||||
* be @p pc has failed to obtain a valid pointer, for example because a memory
|
||||
* allocation that was meant to provide the pointer has failed.
|
||||
* @param[in] pc The program counter at the location that took ownership
|
||||
*/
|
||||
void sli_memory_profiler_track_ownership(sli_memory_tracker_handle_t tracker_handle,
|
||||
void * ptr,
|
||||
void * pc);
|
||||
|
||||
/**
|
||||
* @brief Trigger the creation of a snapshot of the current state
|
||||
*
|
||||
* This function can be used by the device to trigger the analysis software on
|
||||
* the PC or Mac to take a snapshot of the current state of the allocation
|
||||
* bookkeeping. This would typically be used by test cases that communicate with
|
||||
* the device under test and want to synchronously record the state of the
|
||||
* allocations at a known point in the test sequence.
|
||||
*
|
||||
* @param[in] name Short name for the snapshot that is being created. The name
|
||||
* is immediately sent in the RTT event to the analysis software and does not
|
||||
* need to be retained in the device.
|
||||
*/
|
||||
void sli_memory_profiler_take_snapshot(const char *name);
|
||||
|
||||
/**
|
||||
* @brief Output a generic log event in the RTT event stream
|
||||
*
|
||||
* This function is meant to be used for temporary debugging purposes only. When
|
||||
* debugging a memory leak requires visibility to software actions other than
|
||||
* memory allocation or free, calls to this generic logging mechanism can be
|
||||
* added so that the sequence of software events can be seen with respect to the
|
||||
* allocation and free events that are visible in the normal Memory Profiler
|
||||
* events.
|
||||
*
|
||||
* @param[in] log_id Numeric identifier of this log event. This is passed in the
|
||||
* RTT event to the analysis tool and the ID appears in the log produced by
|
||||
* the analyzer but the value is not otherwise used by the Memory Profiler. It
|
||||
* is the responsibility of the caller to use values that are sufficiently
|
||||
* unique that the developer can identify the logs.
|
||||
*
|
||||
* @param[in] arg1 Arbitrary 32-bit argument that's relevant for the developer
|
||||
*
|
||||
* @param[in] arg2 Arbitrary 32-bit argument that's relevant for the developer
|
||||
*
|
||||
* @param[in] arg3 Arbitrary 32-bit argument that's relevant for the developer
|
||||
*
|
||||
* @param[in] pc The program counter at the location of the log call
|
||||
*/
|
||||
void sli_memory_profiler_log(uint32_t log_id,
|
||||
uint32_t arg1,
|
||||
uint32_t arg2,
|
||||
uint32_t arg3,
|
||||
void * pc);
|
||||
|
||||
// The macros expand to their full content only when profiling is included
|
||||
#if SLI_MEMORY_PROFILER_ENABLE_PROFILING
|
||||
|
||||
/**
|
||||
* @brief Macro to wrap calls to @ref sli_memory_profiler_track_alloc
|
||||
*/
|
||||
#define SLI_MEMORY_PROFILER_TRACK_ALLOC(tracker_handle, ptr, size) \
|
||||
do { \
|
||||
sli_memory_profiler_track_alloc((tracker_handle), (ptr), (size)); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* @brief Macro to wrap calls to @ref sli_memory_profiler_track_alloc_with_ownership
|
||||
*
|
||||
* If ownership tracking is disabled at build time, the macro reduces to normal
|
||||
* tracking without ownership.
|
||||
*/
|
||||
#if SLI_MEMORY_PROFILER_ENABLE_OWNERSHIP_TRACKING
|
||||
#define SLI_MEMORY_PROFILER_TRACK_ALLOC_WITH_OWNERSHIP(tracker_handle, ptr, size, pc) \
|
||||
do { \
|
||||
void * volatile _pc = (pc); \
|
||||
sli_memory_profiler_track_alloc_with_ownership((tracker_handle), (ptr), (size), _pc); \
|
||||
} while (0)
|
||||
#else // SLI_MEMORY_PROFILER_ENABLE_OWNERSHIP_TRACKING
|
||||
#define SLI_MEMORY_PROFILER_TRACK_ALLOC_WITH_OWNERSHIP(tracker_handle, ptr, size, pc) \
|
||||
do { \
|
||||
(void) (pc); \
|
||||
sli_memory_profiler_track_alloc((tracker_handle), (ptr), (size)); \
|
||||
} while (0)
|
||||
#endif // SLI_MEMORY_PROFILER_ENABLE_OWNERSHIP_TRACKING
|
||||
|
||||
/**
|
||||
* @brief Macro to wrap calls to @ref sli_memory_profiler_track_realloc
|
||||
*/
|
||||
#define SLI_MEMORY_PROFILER_TRACK_REALLOC(tracker_handle, ptr, realloced_ptr, size) \
|
||||
do { \
|
||||
sli_memory_profiler_track_realloc((tracker_handle), (ptr), (realloced_ptr), (size)); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* @brief Macro to wrap calls to @ref sli_memory_profiler_track_free
|
||||
*/
|
||||
#define SLI_MEMORY_PROFILER_TRACK_FREE(tracker_handle, ptr) \
|
||||
do { \
|
||||
sli_memory_profiler_track_free((tracker_handle), (ptr)); \
|
||||
} while (0)
|
||||
|
||||
#else // SLI_MEMORY_PROFILER_ENABLE_PROFILING
|
||||
|
||||
// Empty implementation of tracking macros when memory profiling calls are
|
||||
// excluded at build time
|
||||
#define SLI_MEMORY_PROFILER_TRACK_ALLOC(tracker_handle, ptr, size) \
|
||||
do { \
|
||||
(void) (tracker_handle); \
|
||||
(void) (ptr); \
|
||||
(void) (size); \
|
||||
} while (0)
|
||||
|
||||
#define SLI_MEMORY_PROFILER_TRACK_ALLOC_WITH_OWNERSHIP(tracker_handle, ptr, size, pc) \
|
||||
do { \
|
||||
(void) (tracker_handle); \
|
||||
(void) (ptr); \
|
||||
(void) (size); \
|
||||
(void) (pc); \
|
||||
} while (0)
|
||||
|
||||
#define SLI_MEMORY_PROFILER_TRACK_REALLOC(tracker_handle, ptr, realloced_ptr, size) \
|
||||
do { \
|
||||
(void) (tracker_handle); \
|
||||
(void) (ptr); \
|
||||
(void) (realloced_ptr); \
|
||||
(void) (size); \
|
||||
} while (0)
|
||||
|
||||
#define SLI_MEMORY_PROFILER_TRACK_FREE(tracker_handle, ptr) \
|
||||
do { \
|
||||
(void) (tracker_handle); \
|
||||
(void) (ptr); \
|
||||
} while (0)
|
||||
|
||||
#endif // SLI_MEMORY_PROFILER_ENABLE_PROFILING
|
||||
|
||||
// Ownership tracking calls are included based on dedicated configuration
|
||||
#if SLI_MEMORY_PROFILER_ENABLE_PROFILING && SLI_MEMORY_PROFILER_ENABLE_OWNERSHIP_TRACKING
|
||||
|
||||
/**
|
||||
* @brief Macro to wrap calls to @ref sli_memory_profiler_track_ownership
|
||||
*/
|
||||
#define SLI_MEMORY_PROFILER_TRACK_OWNERSHIP(ptr, pc) \
|
||||
do { \
|
||||
void * volatile _pc = (pc); \
|
||||
sli_memory_profiler_track_ownership(SLI_INVALID_MEMORY_TRACKER_HANDLE, (ptr), _pc); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* @brief Macro to wrap calls to @ref sli_memory_profiler_track_ownership
|
||||
*/
|
||||
#define SLI_MEMORY_PROFILER_TRACK_OWNERSHIP_ON_TRACKER(tracker_handle, ptr, pc) \
|
||||
do { \
|
||||
void * volatile _pc = (pc); \
|
||||
sli_memory_profiler_track_ownership((tracker_handle), (ptr), _pc); \
|
||||
} while (0)
|
||||
|
||||
#else // SLI_MEMORY_PROFILER_ENABLE_PROFILING && SLI_MEMORY_PROFILER_ENABLE_OWNERSHIP_TRACKING
|
||||
|
||||
#define SLI_MEMORY_PROFILER_TRACK_OWNERSHIP(ptr, pc) \
|
||||
do { \
|
||||
(void) (ptr); \
|
||||
(void) (pc); \
|
||||
} while (0)
|
||||
|
||||
#define SLI_MEMORY_PROFILER_TRACK_OWNERSHIP_ON_TRACKER(tracker_handle, ptr, pc) \
|
||||
do { \
|
||||
(void) (tracker_handle); \
|
||||
(void) (ptr); \
|
||||
(void) (pc); \
|
||||
} while (0)
|
||||
|
||||
#endif // SLI_MEMORY_PROFILER_ENABLE_PROFILING && SLI_MEMORY_PROFILER_ENABLE_OWNERSHIP_TRACKING
|
||||
|
||||
/** @} end memory_profiler */
|
||||
/// @endcond
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // SLI_MEMORY_PROFILER_H
|
||||
@@ -0,0 +1,126 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief Stub implementation of memory profiler
|
||||
*******************************************************************************
|
||||
* # License
|
||||
* <b>Copyright 2023 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 "sli_memory_profiler.h"
|
||||
#include "sl_status.h"
|
||||
|
||||
/* Create a memory tracker */
|
||||
sl_status_t sli_memory_profiler_create_tracker(sli_memory_tracker_handle_t tracker_handle,
|
||||
const char *description)
|
||||
|
||||
{
|
||||
(void) tracker_handle;
|
||||
(void) description;
|
||||
return SL_STATUS_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
/* Create a pool memory tracker */
|
||||
sl_status_t sli_memory_profiler_create_pool_tracker(sli_memory_tracker_handle_t tracker_handle,
|
||||
const char *description,
|
||||
void* ptr,
|
||||
size_t size)
|
||||
{
|
||||
(void) tracker_handle;
|
||||
(void) description;
|
||||
(void) ptr;
|
||||
(void) size;
|
||||
return SL_STATUS_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
/* Add or update a description to a previously created memory tracker */
|
||||
void sli_memory_profiler_describe_tracker(sli_memory_tracker_handle_t tracker_handle,
|
||||
const char *description)
|
||||
{
|
||||
(void) tracker_handle;
|
||||
(void) description;
|
||||
}
|
||||
|
||||
/* Delete a memory tracker */
|
||||
void sli_memory_profiler_delete_tracker(sli_memory_tracker_handle_t tracker_handle)
|
||||
{
|
||||
(void) tracker_handle;
|
||||
}
|
||||
|
||||
/* Track the allocation of a memory block */
|
||||
void sli_memory_profiler_track_alloc(sli_memory_tracker_handle_t tracker_handle, void * ptr, size_t size)
|
||||
{
|
||||
(void) tracker_handle;
|
||||
(void) ptr;
|
||||
(void) size;
|
||||
}
|
||||
|
||||
/* Track the allocation of a memory block and record ownership */
|
||||
void sli_memory_profiler_track_alloc_with_ownership(sli_memory_tracker_handle_t tracker_handle,
|
||||
void * ptr,
|
||||
size_t size,
|
||||
void * pc)
|
||||
{
|
||||
(void) tracker_handle;
|
||||
(void) ptr;
|
||||
(void) size;
|
||||
(void) pc;
|
||||
}
|
||||
|
||||
/* Track the freeing of a memory block */
|
||||
void sli_memory_profiler_track_free(sli_memory_tracker_handle_t tracker_handle, void * ptr)
|
||||
{
|
||||
(void) tracker_handle;
|
||||
(void) ptr;
|
||||
}
|
||||
|
||||
/* Track the transfer of memory allocation ownership */
|
||||
void sli_memory_profiler_track_ownership(sli_memory_tracker_handle_t tracker_handle,
|
||||
void * ptr,
|
||||
void * pc)
|
||||
{
|
||||
(void) tracker_handle;
|
||||
(void) ptr;
|
||||
(void) pc;
|
||||
}
|
||||
|
||||
/* Trigger the creation of a snapshot of the current state */
|
||||
void sli_memory_profiler_take_snapshot(const char *name)
|
||||
{
|
||||
(void) name;
|
||||
}
|
||||
|
||||
/* Send a generic log */
|
||||
void sli_memory_profiler_log(uint32_t log_id,
|
||||
uint32_t arg1,
|
||||
uint32_t arg2,
|
||||
uint32_t arg3,
|
||||
void * pc)
|
||||
{
|
||||
(void) log_id;
|
||||
(void) arg1;
|
||||
(void) arg2;
|
||||
(void) arg3;
|
||||
(void) pc;
|
||||
}
|
||||
1200
Libs/platform/service/memory_manager/src/sl_memory_manager.c
Normal file
1200
Libs/platform/service/memory_manager/src/sl_memory_manager.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,212 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief Memory Manager Driver's C++ Implementation.
|
||||
*******************************************************************************
|
||||
* # License
|
||||
* <b>Copyright 2023 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 <cstddef>
|
||||
|
||||
#include "sl_memory_manager.h"
|
||||
#include "sl_assert.h"
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// MEMORY MANAGER PRE-INITIALIZATION
|
||||
|
||||
#if defined (__GNUC__)
|
||||
/***************************************************************************//**
|
||||
* Initializes the memory manager.
|
||||
*
|
||||
* @note With a C++ application, the memory manager requires to be initialized
|
||||
* prior to any malloc() done in any static global objects' constructors.
|
||||
*
|
||||
* This function is called after copying in RAM the .data section
|
||||
* (initialized global variables) and zeroing the .bss section (non-initialized
|
||||
* global variables) and before the main() entry point. The function is placed
|
||||
* in a special section called .preinit_array. preinit_array hold pointers
|
||||
* to functions that should be executed before any other initialization
|
||||
* functions, including C++ static constructors. It allows very early
|
||||
* initialization tasks that need to be completed before any dynamic linking
|
||||
* or library initialization occurs.
|
||||
*
|
||||
* When sl_memory_init() is called early during the GCC/G++ startup code,
|
||||
* sl_memory_init() is not called by the component sl_system.
|
||||
******************************************************************************/
|
||||
static void sl_memory_preinit(void) {
|
||||
sl_memory_init();
|
||||
}
|
||||
|
||||
__attribute__((used, section(".preinit_array")))
|
||||
static void (*preinit_array)(void) = sl_memory_preinit;
|
||||
#endif
|
||||
|
||||
#if defined(__IAR_SYSTEMS_ICC__)
|
||||
/***************************************************************************//**
|
||||
* Initializes the memory manager.
|
||||
*
|
||||
* @note This special C++ class and its associated global object allows the
|
||||
* memory manager sl_memory_init() to be initialized prior to any malloc() done
|
||||
* in any static global objects' constructors.
|
||||
* It serves the same purpose as the C function sl_memory_preinit() used for
|
||||
* GCC/G++ early initialization above. It will use the special section
|
||||
* .preinit_array.
|
||||
*
|
||||
* The IAR "#pragma early_dynamic_initialization" marks certain global objects
|
||||
* for earlier initialization by registering their constructor to the
|
||||
* .preinit_array section. When sl_memory_init() is called early during the
|
||||
* IAR startup code (i.e. after copying in RAM the .data section
|
||||
* (initialized global variables) and zeroing the .bss section (non-initialized
|
||||
* global variables) and before the main() entry point), sl_memory_init()
|
||||
* is not called by the component sl_system.
|
||||
******************************************************************************/
|
||||
#pragma early_dynamic_initialization
|
||||
class sl_memory_preinit
|
||||
{
|
||||
public:
|
||||
sl_memory_preinit()
|
||||
{
|
||||
sl_memory_init();
|
||||
}
|
||||
|
||||
~sl_memory_preinit()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
sl_memory_preinit sl_memory_preinit_obj;
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// GLOBAL C++ NEW/DELETE OVERLOAD
|
||||
|
||||
/***************************************************************************//**
|
||||
* Overloaded new operator.
|
||||
* Allocates a memory block of at least requested size from the heap.
|
||||
*
|
||||
* @param[in] size Size of the block, in bytes.
|
||||
*
|
||||
* @return Pointer to allocated block if successful. Null pointer if
|
||||
* allocation failed.
|
||||
******************************************************************************/
|
||||
void *operator new(size_t size)
|
||||
{
|
||||
void *block = NULL;
|
||||
sl_status_t status;
|
||||
|
||||
status = sl_memory_alloc(size, BLOCK_TYPE_LONG_TERM, (void **)&block);
|
||||
if (status != SL_STATUS_OK) {
|
||||
// Convert C NULL pointer to C++ dedicated type.
|
||||
block = nullptr;
|
||||
}
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Overloaded delete operator used for single object allocations.
|
||||
* Frees a previously allocated block back into the heap.
|
||||
*
|
||||
* @param[in] ptr Pointer to memory block to be freed.
|
||||
******************************************************************************/
|
||||
void operator delete(void *ptr)
|
||||
{
|
||||
sl_status_t status;
|
||||
|
||||
status = sl_memory_free(ptr);
|
||||
if (status != SL_STATUS_OK) {
|
||||
EFM_ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Overloaded delete operator used for array of objects allocations.
|
||||
* Frees a previously allocated block back into the heap.
|
||||
*
|
||||
* @param[in] ptr Pointer to memory block to be freed.
|
||||
******************************************************************************/
|
||||
void operator delete[](void *ptr)
|
||||
{
|
||||
sl_status_t status;
|
||||
|
||||
status = sl_memory_free(ptr);
|
||||
if (status != SL_STATUS_OK) {
|
||||
EFM_ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Overloaded delete operator for single object allocations.
|
||||
* Frees a previously allocated block back into the heap.
|
||||
*
|
||||
* @param[in] ptr Pointer to memory block to be freed.
|
||||
* @param[in] size Size of block to be freed, in bytes.
|
||||
*
|
||||
* @note The -Wsized-deallocation option in G++ is a warning option related
|
||||
* to C++17 and later versions. This other overloaded version of delete
|
||||
* is recommended by -Wsized-deallocation option for C++17. Indeed,
|
||||
* certain standard containers (e.g. vector, list) with C++17 use a delete
|
||||
* that needs to provide a 'size' parameter. The Memory Manager
|
||||
* does not provide a free() function taking a 'size' parameter. Hence,
|
||||
* the 'size' parameter is simply ignored. When compiling with C++11,
|
||||
* the same containers such as vector, list will use an overloaded delete
|
||||
* without a 'size' parameter.
|
||||
* The -Wsized-deallocation option is used to catch situations where
|
||||
* you might be using the delete operator incorrectly with pointers
|
||||
* that were not allocated with new or that were allocated with a type
|
||||
* that doesn't have a suitable operator delete.
|
||||
******************************************************************************/
|
||||
void operator delete(void *ptr,
|
||||
size_t size)
|
||||
{
|
||||
sl_status_t status;
|
||||
|
||||
(void)size;
|
||||
|
||||
status = sl_memory_free(ptr);
|
||||
if (status != SL_STATUS_OK) {
|
||||
EFM_ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Overloaded delete operator used for array of objects allocations.
|
||||
* Frees a previously allocated block back into the heap.
|
||||
*
|
||||
* @param[in] ptr Pointer to memory block to be freed.
|
||||
* @param[in] size Size of block to be freed, in bytes.
|
||||
******************************************************************************/
|
||||
void operator delete[](void *ptr,
|
||||
size_t size)
|
||||
{
|
||||
sl_status_t status;
|
||||
|
||||
(void)size;
|
||||
|
||||
status = sl_memory_free(ptr);
|
||||
if (status != SL_STATUS_OK) {
|
||||
EFM_ASSERT(false);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,377 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief Memory Manager Driver's Block Reservation Feature Implementation.
|
||||
*******************************************************************************
|
||||
* # License
|
||||
* <b>Copyright 2023 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 <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdalign.h>
|
||||
|
||||
#include "sl_memory_manager_config.h"
|
||||
#include "sl_memory_manager.h"
|
||||
#include "sli_memory_manager.h"
|
||||
#include "sl_assert.h"
|
||||
#include "sl_bit.h"
|
||||
#include "sl_common.h"
|
||||
|
||||
#if defined(SL_COMPONENT_CATALOG_PRESENT)
|
||||
#include "sl_component_catalog.h"
|
||||
#endif
|
||||
|
||||
#if defined(SL_CATALOG_MEMORY_PROFILER_PRESENT)
|
||||
#include "sli_memory_profiler.h"
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
************************** GLOBAL FUNCTIONS *******************************
|
||||
******************************************************************************/
|
||||
|
||||
/***************************************************************************//**
|
||||
* Dynamically reserves a block of memory.
|
||||
*
|
||||
* @note (1) This function assumes the 'handle' is provided by the caller:
|
||||
* - either statically (e.g. as a global variable)
|
||||
* - or dynamically by calling sl_memory_reservation_handle_alloc().
|
||||
******************************************************************************/
|
||||
sl_status_t sl_memory_reserve_block(size_t size,
|
||||
size_t align,
|
||||
sl_memory_reservation_t *handle,
|
||||
void **block)
|
||||
{
|
||||
#if defined(SL_CATALOG_MEMORY_PROFILER_PRESENT)
|
||||
void * volatile return_address = sli_memory_profiler_get_return_address();
|
||||
#endif
|
||||
|
||||
// Check proper alignment characteristics.
|
||||
EFM_ASSERT((align == SL_MEMORY_BLOCK_ALIGN_DEFAULT)
|
||||
|| (SL_MATH_IS_PWR2(align)
|
||||
&& (align <= SL_MEMORY_BLOCK_ALIGN_512_BYTES)));
|
||||
|
||||
(void) align;
|
||||
sli_block_metadata_t *free_block_metadata = NULL;
|
||||
void *reserved_blk = NULL;
|
||||
size_t current_block_len;
|
||||
size_t size_real;
|
||||
size_t size_adjusted;
|
||||
size_t block_size_remaining;
|
||||
sl_memory_region_t heap_region = sl_memory_get_heap_region();
|
||||
#if defined(DEBUG_EFM) || defined(DEBUG_EFM_USER)
|
||||
reserve_no_retention_first = false;
|
||||
#endif
|
||||
|
||||
// Verify that the handle pointer isn't NULL. See Note #1.
|
||||
if ((handle == NULL) || (block == NULL)) {
|
||||
return SL_STATUS_NULL_POINTER;
|
||||
}
|
||||
|
||||
// Check that the block does not exist yet.
|
||||
if ((handle->block_size != 0) || (handle->block_address != NULL)) {
|
||||
return SL_STATUS_FAIL;
|
||||
}
|
||||
|
||||
*block = NULL; // No block reserved yet.
|
||||
|
||||
if ((size == 0) || (size >= heap_region.size)) {
|
||||
return SL_STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
size_real = SLI_ALIGN_ROUND_UP(size, SLI_BLOCK_ALLOC_MIN_ALIGN);
|
||||
|
||||
CORE_DECLARE_IRQ_STATE;
|
||||
CORE_ENTER_ATOMIC();
|
||||
|
||||
// For block reservations, the size_adjusted contains the metadata.
|
||||
size_adjusted = sli_memory_find_free_block(size_real, align, BLOCK_TYPE_SHORT_TERM, true, &free_block_metadata);
|
||||
|
||||
if ((free_block_metadata == NULL) || (size_adjusted == 0)) {
|
||||
CORE_EXIT_ATOMIC();
|
||||
#if defined(SL_CATALOG_MEMORY_PROFILER_PRESENT)
|
||||
sli_memory_profiler_track_alloc_with_ownership(sli_mm_heap_name, NULL, size, return_address);
|
||||
#endif
|
||||
return SL_STATUS_ALLOCATION_FAILED;
|
||||
}
|
||||
|
||||
current_block_len = SLI_BLOCK_LEN_DWORD_TO_BYTE(free_block_metadata->length);
|
||||
// SLI_BLOCK_METADATA_SIZE_BYTE is added to the free block length to get the real remaining size as size_adjusted contains the metadata size.
|
||||
block_size_remaining = (current_block_len + SLI_BLOCK_METADATA_SIZE_BYTE) - size_adjusted;
|
||||
|
||||
// Create a new block = reserved block returned to requester. This new block is the nearest to the heap end.
|
||||
reserved_blk = (sli_block_metadata_t *)((uint8_t *)free_block_metadata + block_size_remaining);
|
||||
|
||||
sli_free_blocks_number--;
|
||||
|
||||
// Split free and reserved blocks if possible.
|
||||
if (block_size_remaining >= SLI_BLOCK_RESERVATION_MIN_SIZE_BYTE) {
|
||||
// Changes size of free block.
|
||||
free_block_metadata->length -= SLI_BLOCK_LEN_BYTE_TO_DWORD(size_real);
|
||||
|
||||
// Account for the split block that is free.
|
||||
sli_free_blocks_number++;
|
||||
} else {
|
||||
sli_block_metadata_t *neighbour_block = NULL;
|
||||
|
||||
// Update next neighbour.
|
||||
if (free_block_metadata->offset_neighbour_next != 0) {
|
||||
neighbour_block = (sli_block_metadata_t *)((uint64_t *)free_block_metadata + free_block_metadata->offset_neighbour_next);
|
||||
|
||||
if (free_block_metadata->offset_neighbour_prev != 0) {
|
||||
neighbour_block->offset_neighbour_prev += free_block_metadata->offset_neighbour_prev;
|
||||
} else {
|
||||
// Heap start.
|
||||
neighbour_block->offset_neighbour_next = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Update previous neighbour.
|
||||
if (free_block_metadata->offset_neighbour_prev != 0) {
|
||||
neighbour_block = (sli_block_metadata_t *)((uint64_t *)free_block_metadata - free_block_metadata->offset_neighbour_prev);
|
||||
|
||||
if (free_block_metadata->offset_neighbour_next != 0) {
|
||||
neighbour_block->offset_neighbour_next += free_block_metadata->offset_neighbour_next;
|
||||
} else {
|
||||
// Heap end.
|
||||
neighbour_block->offset_neighbour_next = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Update head pointers accordingly.
|
||||
sli_update_free_list_heads(neighbour_block, free_block_metadata, true);
|
||||
}
|
||||
|
||||
CORE_EXIT_ATOMIC();
|
||||
|
||||
handle->block_size = size;
|
||||
handle->block_address = reserved_blk;
|
||||
*block = reserved_blk;
|
||||
|
||||
#ifdef SLI_MEMORY_MANAGER_ENABLE_TEST_UTILITIES
|
||||
// Save the reservation for heap integrity check purposes.
|
||||
sli_memory_save_reservation_handle(handle, align);
|
||||
#endif
|
||||
|
||||
#if defined(SL_CATALOG_MEMORY_PROFILER_PRESENT)
|
||||
sli_memory_profiler_track_alloc(sli_mm_heap_name, handle->block_address, size_real);
|
||||
sli_memory_profiler_track_alloc_with_ownership(sli_mm_heap_reservation_name,
|
||||
handle->block_address,
|
||||
handle->block_size,
|
||||
return_address);
|
||||
#endif
|
||||
|
||||
return SL_STATUS_OK;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Frees a dynamically reserved block of memory.
|
||||
*
|
||||
* @note (1) Block reservation are not part of the double linked-list as they
|
||||
* don't have metadata next to them compared to a LT/ST block that
|
||||
* has a metadata with offset. When releasing a reserved block,
|
||||
* the previous and next blocks that are part of the double linked-list
|
||||
* need to be found to insert this new free block. The neighbours are
|
||||
* found by browsing through the linked-list from the heap start until
|
||||
* a block metadata's address is higher than the block being
|
||||
* released's address. The previous and next blocks are then saved to
|
||||
* properly update the double linked-list.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_memory_release_block(sl_memory_reservation_t *handle)
|
||||
{
|
||||
sl_memory_region_t heap_region = sl_memory_get_heap_region();
|
||||
|
||||
uint16_t new_free_block_length;
|
||||
sli_block_metadata_t *new_free_block = NULL;
|
||||
sli_block_metadata_t *prev_block = NULL;
|
||||
sli_block_metadata_t *next_block = NULL;
|
||||
uint16_t reserved_block_offset;
|
||||
|
||||
sli_block_metadata_t *current_metadata = (sli_block_metadata_t *)heap_region.addr;
|
||||
|
||||
// Verify that the handle isn't NULL.
|
||||
if (handle == NULL) {
|
||||
return SL_STATUS_NULL_POINTER;
|
||||
}
|
||||
|
||||
#if defined(SL_CATALOG_MEMORY_PROFILER_PRESENT)
|
||||
sli_memory_profiler_track_free(sli_mm_heap_name, handle->block_address);
|
||||
#endif
|
||||
|
||||
CORE_DECLARE_IRQ_STATE;
|
||||
CORE_ENTER_ATOMIC();
|
||||
|
||||
// Find neighbours by searching from the heap start. See Note #1.
|
||||
while ((uintptr_t)current_metadata < (uintptr_t)handle->block_address) {
|
||||
prev_block = current_metadata;
|
||||
|
||||
if (current_metadata->offset_neighbour_next == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
current_metadata = (sli_block_metadata_t *)((uint64_t *)current_metadata + current_metadata->offset_neighbour_next);
|
||||
}
|
||||
next_block = ((uintptr_t)current_metadata >= (uintptr_t)handle->block_address) ? current_metadata : NULL;
|
||||
|
||||
new_free_block = (sli_block_metadata_t *)handle->block_address;
|
||||
new_free_block_length = (uint16_t)SLI_BLOCK_LEN_BYTE_TO_DWORD(handle->block_size) - SLI_BLOCK_METADATA_SIZE_DWORD;
|
||||
|
||||
// Create a new free block while trying to merge it with the previous and next free blocks if possible.
|
||||
if (prev_block != NULL) {
|
||||
// Calculate offset between the reserved block and the previous block's payload address.
|
||||
reserved_block_offset = (uint16_t)((uint64_t *)handle->block_address - (uint64_t *)prev_block - SLI_BLOCK_METADATA_SIZE_DWORD);
|
||||
// Then calculate the difference between the above offset and the length of the previous block.
|
||||
reserved_block_offset -= prev_block->length;
|
||||
|
||||
// Make sure there's no reserved block between the freed block and the previous block.
|
||||
// Layout around the reserved block to free (aka R1) will be:
|
||||
// |...|Metadata Free block|Data Free block|R1||
|
||||
if ((prev_block->block_in_use == 0) && (reserved_block_offset < SLI_BLOCK_RESERVATION_MIN_SIZE_DWORD)) {
|
||||
// New freed block's previous block is free, so merge both free blocks.
|
||||
new_free_block = prev_block;
|
||||
prev_block = (sli_block_metadata_t *)((uint64_t *)prev_block - prev_block->offset_neighbour_prev);
|
||||
new_free_block_length += new_free_block->length + SLI_BLOCK_METADATA_SIZE_DWORD;
|
||||
} else {
|
||||
// Create a new free block, because previous block is a dynamic allocation, a reserved block or the start of the heap.
|
||||
// Layout around the reserved block to free (aka R1) will be:
|
||||
// |...|Metadata Free block|Data Free block|R2|R1|| or |...|Metadata ST1|Data ST1|R1|| or |...|Metadata LT|Data LT|R1||
|
||||
sli_free_blocks_number++;
|
||||
}
|
||||
}
|
||||
|
||||
if (next_block != NULL) {
|
||||
// Calculate offset between the reserved block and the next block.
|
||||
reserved_block_offset = (uint16_t)((uint64_t *)next_block - (uint64_t *)handle->block_address);
|
||||
// Then calculate the difference between the above offset and the size of the block being released.
|
||||
reserved_block_offset -= SLI_BLOCK_LEN_BYTE_TO_DWORD(handle->block_size);
|
||||
|
||||
// Make sure there's no reserved block between the freed block and the next block.
|
||||
if ((next_block->block_in_use == 0) && (reserved_block_offset < SLI_BLOCK_RESERVATION_MIN_SIZE_DWORD)) {
|
||||
// New freed block's following block is free, so merge both free blocks.
|
||||
new_free_block_length += next_block->length + reserved_block_offset + SLI_BLOCK_METADATA_SIZE_DWORD;
|
||||
// Invalidate the next block metadata.
|
||||
next_block->length = 0;
|
||||
// 2 free blocks have been merged, account for 1 free block only.
|
||||
sli_free_blocks_number--;
|
||||
|
||||
if (next_block->offset_neighbour_next != 0) {
|
||||
// Get next block following current next block.
|
||||
next_block = (sli_block_metadata_t *)((uint64_t *)next_block + next_block->offset_neighbour_next);
|
||||
} else {
|
||||
next_block = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update the new free metadata block accordingly.
|
||||
sli_memory_metadata_init(new_free_block);
|
||||
new_free_block->length = new_free_block_length;
|
||||
|
||||
if (next_block != NULL) {
|
||||
new_free_block->offset_neighbour_next = (uint16_t)((uint64_t *)next_block - (uint64_t *)new_free_block);
|
||||
next_block->offset_neighbour_prev = new_free_block->offset_neighbour_next;
|
||||
} else {
|
||||
// Heap end.
|
||||
new_free_block->offset_neighbour_next = 0;
|
||||
}
|
||||
|
||||
if (prev_block != NULL) {
|
||||
new_free_block->offset_neighbour_prev = (uint16_t)((uint64_t *)new_free_block - (uint64_t *)prev_block);
|
||||
prev_block->offset_neighbour_next = new_free_block->offset_neighbour_prev;
|
||||
} else {
|
||||
// Heap start.
|
||||
new_free_block->offset_neighbour_prev = 0;
|
||||
}
|
||||
|
||||
if (sli_free_lt_list_head == NULL // LT list is empty. Freed block becomes the new 1st element.
|
||||
|| sli_free_lt_list_head > new_free_block // LT list not empty. Verify if freed block becomes the head.
|
||||
|| sli_free_lt_list_head->length == 0) {
|
||||
sli_free_lt_list_head = new_free_block;
|
||||
}
|
||||
|
||||
if (sli_free_st_list_head == NULL // ST list is empty. Freed block becomes the new 1st element.
|
||||
|| sli_free_st_list_head < new_free_block // ST list not empty. Verify if freed block becomes the head.
|
||||
|| sli_free_st_list_head->length == 0) {
|
||||
sli_free_st_list_head = new_free_block;
|
||||
}
|
||||
|
||||
// Invalidate handle.
|
||||
handle->block_address = NULL;
|
||||
handle->block_size = 0;
|
||||
|
||||
CORE_EXIT_ATOMIC();
|
||||
|
||||
#ifdef SLI_MEMORY_MANAGER_ENABLE_TEST_UTILITIES
|
||||
sli_memory_remove_reservation_handle(handle);
|
||||
#endif
|
||||
|
||||
return SL_STATUS_OK;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Dynamically allocates a block reservation handle.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_memory_reservation_handle_alloc(sl_memory_reservation_t **handle)
|
||||
{
|
||||
#if defined(SL_CATALOG_MEMORY_PROFILER_PRESENT)
|
||||
void * volatile return_address = sli_memory_profiler_get_return_address();
|
||||
#endif
|
||||
sl_status_t status;
|
||||
|
||||
status = sl_memory_alloc(sizeof(sl_memory_reservation_t), BLOCK_TYPE_LONG_TERM, (void**)handle);
|
||||
#if defined(SL_CATALOG_MEMORY_PROFILER_PRESENT)
|
||||
sli_memory_profiler_track_ownership(SLI_INVALID_MEMORY_TRACKER_HANDLE, *handle, return_address);
|
||||
#endif
|
||||
if (status != SL_STATUS_OK) {
|
||||
return status;
|
||||
}
|
||||
|
||||
// Initialize handle data.
|
||||
(*handle)->block_address = NULL;
|
||||
(*handle)->block_size = 0;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Frees a dynamically allocated block reservation handle.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_memory_reservation_handle_free(sl_memory_reservation_t *handle)
|
||||
{
|
||||
// Check that block has been released before freeing handle.
|
||||
if ((handle->block_size != 0) || (handle->block_address != NULL)) {
|
||||
return SL_STATUS_FAIL;
|
||||
}
|
||||
|
||||
return sl_memory_free((void *)handle);
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets the size of the memory reservation handle structure.
|
||||
******************************************************************************/
|
||||
uint32_t sl_memory_reservation_handle_get_size(void)
|
||||
{
|
||||
return sizeof(sl_memory_reservation_t);
|
||||
}
|
||||
@@ -0,0 +1,242 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief Memory Manager Driver's Memory Pool Lightweight Feature Implementation.
|
||||
*******************************************************************************
|
||||
* # License
|
||||
* <b>Copyright 2023 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 <string.h>
|
||||
|
||||
#include "sl_memory_manager.h"
|
||||
#include "sli_memory_manager.h"
|
||||
#include "sl_assert.h"
|
||||
#include "sl_core.h"
|
||||
|
||||
#if defined(SL_COMPONENT_CATALOG_PRESENT)
|
||||
#include "sl_component_catalog.h"
|
||||
#endif
|
||||
|
||||
#if defined(SL_CATALOG_MEMORY_PROFILER_PRESENT)
|
||||
#include "sli_memory_profiler.h"
|
||||
#endif
|
||||
|
||||
#define SLI_MEM_POOL_OUT_OF_MEMORY 0xFFFFFFFF
|
||||
#define SLI_MEM_POOL_REQUIRED_PADDING(obj_size) (((sizeof(size_t) - ((obj_size) % sizeof(size_t))) % sizeof(size_t)))
|
||||
|
||||
/***************************************************************************//**
|
||||
* Creates a memory pool.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_memory_create_pool(size_t block_size,
|
||||
uint32_t block_count,
|
||||
sl_memory_pool_t *pool_handle)
|
||||
{
|
||||
#if defined(SL_CATALOG_MEMORY_PROFILER_PRESENT)
|
||||
void * volatile return_address = sli_memory_profiler_get_return_address();
|
||||
#endif
|
||||
sl_status_t status = SL_STATUS_OK;
|
||||
uint8_t *block = NULL;
|
||||
size_t block_addr;
|
||||
size_t pool_size;
|
||||
EFM_ASSERT(block_count != 0);
|
||||
EFM_ASSERT(block_size != 0);
|
||||
|
||||
if (pool_handle == NULL) {
|
||||
return SL_STATUS_NULL_POINTER;
|
||||
}
|
||||
|
||||
// SLI_MEM_POOL_REQUIRED_PADDING Rounds up to the nearest platform-dependant size. On a 32-bit processor,
|
||||
// it will be rounded-up to 4 bytes. E.g. 101 bytes will be rounded up to 104 bytes.
|
||||
pool_handle->block_size = block_size + (uint16_t)SLI_MEM_POOL_REQUIRED_PADDING(block_size);
|
||||
pool_handle->block_count = block_count;
|
||||
|
||||
// Reserve a block in which the entire pool will reside. Uses a long term allocation to keep
|
||||
// behavior similar to dynamic reservation.
|
||||
pool_size = pool_handle->block_size * pool_handle->block_count;
|
||||
status = sl_memory_alloc(pool_size, BLOCK_TYPE_LONG_TERM, (void **)&block);
|
||||
|
||||
#if defined(SL_CATALOG_MEMORY_PROFILER_PRESENT)
|
||||
sli_memory_profiler_track_ownership(SLI_INVALID_MEMORY_TRACKER_HANDLE, block, return_address);
|
||||
#endif
|
||||
|
||||
if (status != SL_STATUS_OK) {
|
||||
return status;
|
||||
}
|
||||
|
||||
#if defined(SL_CATALOG_MEMORY_PROFILER_PRESENT)
|
||||
// Create the tracker for the pool with no description. The code that created
|
||||
// the pool can add the tracker description if relevant.
|
||||
sli_memory_profiler_create_pool_tracker(pool_handle, NULL, block, pool_size);
|
||||
#endif
|
||||
|
||||
pool_handle->block_address = (void *)block;
|
||||
|
||||
// Returned block pointer not used because its reference is already stored in block_address.
|
||||
(void)█
|
||||
|
||||
pool_handle->block_free = (uint32_t *)pool_handle->block_address;
|
||||
|
||||
block_addr = (size_t)pool_handle->block_address;
|
||||
|
||||
// Populate the list of free blocks except the last block.
|
||||
for (uint16_t i = 0; i < (block_count - 1); i++) {
|
||||
*(size_t *)block_addr = block_addr + pool_handle->block_size;
|
||||
block_addr += pool_handle->block_size;
|
||||
}
|
||||
|
||||
// Last element will indicate out of memory.
|
||||
*(size_t *)block_addr = SLI_MEM_POOL_OUT_OF_MEMORY;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Deletes a memory pool.
|
||||
*
|
||||
* @note The pool_handle provided is neither freed or invalidated. It can be
|
||||
* reused in a new call to sl_memory_create_pool() to create another pool.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_memory_delete_pool(sl_memory_pool_t *pool_handle)
|
||||
{
|
||||
sl_status_t status;
|
||||
|
||||
// Verify that the handle pointer isn't NULL.
|
||||
if (pool_handle == NULL) {
|
||||
return SL_STATUS_NULL_POINTER;
|
||||
}
|
||||
|
||||
#if defined(SL_CATALOG_MEMORY_PROFILER_PRESENT)
|
||||
// Delete the memory tracker
|
||||
sli_memory_profiler_delete_tracker(pool_handle);
|
||||
#endif
|
||||
|
||||
// Free block.
|
||||
status = sl_memory_free(pool_handle->block_address);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Allocates a block from a memory pool.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_memory_pool_alloc(sl_memory_pool_t *pool_handle,
|
||||
void **block)
|
||||
{
|
||||
#if defined(SL_CATALOG_MEMORY_PROFILER_PRESENT)
|
||||
void * volatile return_address = sli_memory_profiler_get_return_address();
|
||||
#endif
|
||||
CORE_DECLARE_IRQ_STATE;
|
||||
|
||||
if ((pool_handle == NULL) || (block == NULL)) {
|
||||
return SL_STATUS_NULL_POINTER;
|
||||
}
|
||||
|
||||
// No block allocated yet.
|
||||
*block = NULL;
|
||||
|
||||
CORE_ENTER_ATOMIC();
|
||||
|
||||
if ((size_t)pool_handle->block_free == SLI_MEM_POOL_OUT_OF_MEMORY) {
|
||||
CORE_EXIT_ATOMIC();
|
||||
#if defined(SL_CATALOG_MEMORY_PROFILER_PRESENT)
|
||||
sli_memory_profiler_track_alloc_with_ownership(pool_handle, NULL, pool_handle->block_size, return_address);
|
||||
#endif
|
||||
return SL_STATUS_EMPTY;
|
||||
}
|
||||
|
||||
// Get the next free block.
|
||||
void *block_addr = pool_handle->block_free;
|
||||
|
||||
// Update the next free block using the address saved in that block.
|
||||
pool_handle->block_free = (void *)*(size_t *)block_addr;
|
||||
|
||||
CORE_EXIT_ATOMIC();
|
||||
|
||||
#if defined(SL_CATALOG_MEMORY_PROFILER_PRESENT)
|
||||
sli_memory_profiler_track_alloc_with_ownership(pool_handle, block_addr, pool_handle->block_size, return_address);
|
||||
#endif
|
||||
|
||||
*block = block_addr;
|
||||
|
||||
return SL_STATUS_OK;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Frees a block from a memory pool.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_memory_pool_free(sl_memory_pool_t *pool_handle,
|
||||
void *block)
|
||||
{
|
||||
CORE_DECLARE_IRQ_STATE;
|
||||
|
||||
if ((pool_handle == NULL) || (block == NULL)) {
|
||||
return SL_STATUS_NULL_POINTER;
|
||||
}
|
||||
|
||||
// Validate that the provided address is in the pool payload range.
|
||||
EFM_ASSERT((block >= pool_handle->block_address) \
|
||||
&& ((size_t)block <= ((size_t)pool_handle->block_address + (pool_handle->block_size * pool_handle->block_count))));
|
||||
|
||||
#if defined(SL_CATALOG_MEMORY_PROFILER_PRESENT)
|
||||
sli_memory_profiler_track_free(pool_handle, block);
|
||||
#endif
|
||||
|
||||
CORE_ENTER_ATOMIC();
|
||||
|
||||
// Save the current free block address in this block.
|
||||
*(size_t *)block = (size_t)pool_handle->block_free;
|
||||
pool_handle->block_free = block;
|
||||
|
||||
CORE_EXIT_ATOMIC();
|
||||
|
||||
return SL_STATUS_OK;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets the count of free blocks in a memory pool.
|
||||
******************************************************************************/
|
||||
uint32_t sl_memory_pool_get_free_block_count(const sl_memory_pool_t *pool_handle)
|
||||
{
|
||||
uint32_t free_block_count = 0;
|
||||
uint32_t *free_block;
|
||||
|
||||
if (pool_handle == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
CORE_DECLARE_IRQ_STATE;
|
||||
CORE_ENTER_ATOMIC();
|
||||
|
||||
free_block = pool_handle->block_free;
|
||||
|
||||
// Go through the free block list and count the number of free blocks remaining.
|
||||
while ((size_t)free_block != SLI_MEM_POOL_OUT_OF_MEMORY) {
|
||||
free_block = *(uint32_t **)free_block;
|
||||
free_block_count++;
|
||||
}
|
||||
|
||||
CORE_EXIT_ATOMIC();
|
||||
|
||||
return free_block_count;
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief Memory Manager Driver's Memory Pool Common 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_memory_manager.h"
|
||||
|
||||
#if defined(SL_COMPONENT_CATALOG_PRESENT)
|
||||
#include "sl_component_catalog.h"
|
||||
#endif
|
||||
|
||||
#if defined(SL_CATALOG_MEMORY_PROFILER_PRESENT)
|
||||
#include "sli_memory_profiler.h"
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
************************** GLOBAL FUNCTIONS *******************************
|
||||
******************************************************************************/
|
||||
|
||||
/***************************************************************************//**
|
||||
* Dynamically allocates a memory pool handle.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_memory_pool_handle_alloc(sl_memory_pool_t **pool_handle)
|
||||
{
|
||||
#if defined(SL_CATALOG_MEMORY_PROFILER_PRESENT)
|
||||
void * volatile return_address = sli_memory_profiler_get_return_address();
|
||||
#endif
|
||||
sl_status_t status;
|
||||
|
||||
// Allocate pool_handle as a long-term block.
|
||||
status = sl_memory_alloc(sizeof(sl_memory_pool_t), BLOCK_TYPE_LONG_TERM, (void **)pool_handle);
|
||||
|
||||
#if defined(SL_CATALOG_MEMORY_PROFILER_PRESENT)
|
||||
sli_memory_profiler_track_ownership(SLI_INVALID_MEMORY_TRACKER_HANDLE, *pool_handle, return_address);
|
||||
#endif
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Frees a dynamically allocated memory pool handle.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_memory_pool_handle_free(sl_memory_pool_t *pool_handle)
|
||||
{
|
||||
sl_status_t status;
|
||||
|
||||
// Free memory pool_handle.
|
||||
status = sl_memory_free((void *)pool_handle);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets the size of the memory pool handle structure.
|
||||
******************************************************************************/
|
||||
uint32_t sl_memory_pool_handle_get_size(void)
|
||||
{
|
||||
return sizeof(sl_memory_pool_t);
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets the total count of blocks in a memory pool.
|
||||
******************************************************************************/
|
||||
uint32_t sl_memory_pool_get_total_block_count(const sl_memory_pool_t *pool_handle)
|
||||
{
|
||||
if (pool_handle == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return pool_handle->block_count;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets the count of used blocks in a memory pool.
|
||||
******************************************************************************/
|
||||
uint32_t sl_memory_pool_get_used_block_count(const sl_memory_pool_t *pool_handle)
|
||||
{
|
||||
uint32_t used_block_count = 0;
|
||||
|
||||
if (pool_handle == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
used_block_count = pool_handle->block_count - sl_memory_pool_get_free_block_count(pool_handle);
|
||||
|
||||
return used_block_count;
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief Getters for Heap and stack
|
||||
*******************************************************************************
|
||||
* # 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 <stdint.h>
|
||||
#include "em_device.h"
|
||||
#include "sl_memory_manager_region.h"
|
||||
#include "sl_memory_manager_region_config.h"
|
||||
#include "sl_component_catalog.h"
|
||||
|
||||
#define IAR_HEAP_BLOCK_NAME "MEMORY_MANAGER_HEAP"
|
||||
|
||||
// Prevent's compilation errors when building in simulation.
|
||||
#ifndef __USED
|
||||
#define __USED
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__)
|
||||
// Declare stack object used with GCC.
|
||||
static char sl_stack[SL_STACK_SIZE] __attribute__ ((aligned(8), used, section(".stack")));
|
||||
|
||||
/*
|
||||
* Declare the base and limit of the full heap region used with GCC to make
|
||||
* use of otherwise unused memory.
|
||||
*/
|
||||
extern char __HeapBase[];
|
||||
extern char __HeapLimit[];
|
||||
|
||||
#elif defined(__ICCARM__)
|
||||
// Declare stack object used with IAR.
|
||||
__root char sl_stack[SL_STACK_SIZE] @ ".stack";
|
||||
|
||||
#pragma section=IAR_HEAP_BLOCK_NAME
|
||||
|
||||
#endif
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets size and location of the stack.
|
||||
******************************************************************************/
|
||||
sl_memory_region_t sl_memory_get_stack_region(void)
|
||||
{
|
||||
sl_memory_region_t region;
|
||||
|
||||
region.addr = &sl_stack;
|
||||
region.size = SL_STACK_SIZE;
|
||||
return region;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets size and location of the heap.
|
||||
******************************************************************************/
|
||||
sl_memory_region_t sl_memory_get_heap_region(void)
|
||||
{
|
||||
sl_memory_region_t region;
|
||||
|
||||
// Report the actual heap region.
|
||||
#if defined(__GNUC__)
|
||||
region.addr = __HeapBase;
|
||||
region.size = (uintptr_t) __HeapLimit - (uintptr_t) __HeapBase;
|
||||
|
||||
#elif defined(__ICCARM__)
|
||||
region.addr = __section_begin(IAR_HEAP_BLOCK_NAME);
|
||||
region.size = __section_size(IAR_HEAP_BLOCK_NAME);
|
||||
#endif
|
||||
|
||||
return region;
|
||||
}
|
||||
|
||||
#if defined(__GNUC__)
|
||||
/***************************************************************************//**
|
||||
* Extends the process data space.
|
||||
*
|
||||
* @param[in] incr Number of bytes to increment/decrement
|
||||
*
|
||||
* @return Start of the new space allocated if successful. -1 if error.
|
||||
*
|
||||
* @note (1) This is a helper function called by the standard C library
|
||||
* function malloc(). _sbrk() is used to dynamically change the
|
||||
* amount of space allocated for the calling process data segment.
|
||||
* The change is made by allocating the appropriate amount of space
|
||||
* from the end of heap.
|
||||
* _sbrk() adds 'incr' bytes to the end of heap and changes
|
||||
* the allocated space accordingly. 'incr' can be negative, in which
|
||||
* case the amount of allocated space is decreased.
|
||||
*
|
||||
* @note (2) When the Memory Manager (MM) is used, there is no need for
|
||||
* _sbrk() as there is no possible extension with the MM controlling
|
||||
* the entire heap size.
|
||||
* If _sbrk() is called by the standard C library, then the project
|
||||
* may have used the standard C malloc() function implementation.
|
||||
* In that case, the MM retarget, wrapping the GCC malloc() to the
|
||||
* MM sl_malloc(), may have not worked. You may want to double-check
|
||||
* your project settings.
|
||||
******************************************************************************/
|
||||
__USED void * _sbrk(int incr)
|
||||
{
|
||||
#if defined(SL_CATALOG_MEMORY_MANAGER_PRESENT)
|
||||
(void)incr;
|
||||
|
||||
// This means there is an issue with the setup of C standard library. See Note #2.
|
||||
while (1) {
|
||||
// infinite loop
|
||||
}
|
||||
#else
|
||||
static char *heap_end = __HeapBase;
|
||||
char *prev_heap_end;
|
||||
|
||||
if ((heap_end + incr) > __HeapLimit) {
|
||||
// Not enough heap
|
||||
return (void *) -1;
|
||||
}
|
||||
|
||||
prev_heap_end = heap_end;
|
||||
heap_end += incr;
|
||||
|
||||
return prev_heap_end;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,378 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief Memory Manager Driver's Retarget 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_memory_manager.h"
|
||||
|
||||
#if defined(SL_COMPONENT_CATALOG_PRESENT)
|
||||
#include "sl_component_catalog.h"
|
||||
#endif
|
||||
|
||||
#if defined(SL_CATALOG_MEMORY_PROFILER_PRESENT)
|
||||
#include "sli_memory_profiler.h"
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__)
|
||||
// Wrapping a system function with GCC works by using the linker option '--wrap=symbol'.
|
||||
// Any undefined reference to "symbol" will be resolved to "__wrap_symbol".
|
||||
// Any undefined reference to "__real_symbol" will be resolved to "symbol".
|
||||
// In our case, "__real_symbol" is not really required as the retargeted standard
|
||||
// C memory functions will call the corresponding Memory Manager (MM)
|
||||
// native function and not the standard functions again. So it should be seen:
|
||||
// standard _malloc_r() -> MM sl_malloc()
|
||||
// standard _free_r() -> MM sl_free()
|
||||
// standard _calloc_r() -> MM sl_calloc()
|
||||
// standard _realloc_r() -> MM sl_realloc()
|
||||
#define STD_LIB_WRAPPER_MALLOC __wrap__malloc_r
|
||||
#define STD_LIB_WRAPPER_FREE __wrap__free_r
|
||||
#define STD_LIB_WRAPPER_CALLOC __wrap__calloc_r
|
||||
#define STD_LIB_WRAPPER_REALLOC __wrap__realloc_r
|
||||
|
||||
// The GNU gold linker has an issue with LTO and wrapping, where the symbol is
|
||||
// stripped even if it is used in the source code, which leads to link-time errors.
|
||||
// https://sourceware.org/bugzilla/show_bug.cgi?id=24415
|
||||
// By marking the wrapper as externally_visible, the symbol will not be stripped
|
||||
// from the final binary, regardless if it is referenced or not in the source code.
|
||||
#define ATTR_EXT_VIS __attribute__((externally_visible))
|
||||
|
||||
// Reentrant parameter.
|
||||
#define RARG const struct _reent *reent,
|
||||
#define VOID_RARG (void) reent
|
||||
|
||||
#elif defined(__IAR_SYSTEMS_ICC__)
|
||||
// Wrapping a system function works with IAR by patching symbol definitions using $Super$$ and $Sub$$
|
||||
// The $Super$$ special pattern identifies the original unpatched function used for calling
|
||||
// the original function directly.
|
||||
// The $Sub$$ special pattern identifies the new function that is called instead of the
|
||||
// original function.
|
||||
// In our case, $Super$$ is not really required as the retargeted standard
|
||||
// C memory functions will call the corresponding Memory Manager (MM)
|
||||
// native function and not the standard functions again.
|
||||
//
|
||||
// NOTE: IAR supports three separate heap memory handlers: the basic, the advanced, and the no-free
|
||||
// heap handlers.
|
||||
// - If there are calls to heap memory allocation routines in your application, but no calls
|
||||
// to heap deallocation routines, the linker automatically chooses the no-free heap.
|
||||
// - If there are calls to heap memory allocation routines in your application, the linker
|
||||
// automatically chooses the advanced heap.
|
||||
// - If there are calls to heap memory allocation routines in a library for example, the linker
|
||||
// automatically chooses the basic heap.
|
||||
//
|
||||
// Depending on the heap handler type, IAR will select a different malloc/free/calloc/realloc
|
||||
// implementation provided by the IAR system library. That's why, there are different sets of
|
||||
// macros below below to wrap the right IAR standard memory functions with $Sub$$.
|
||||
// - Basic heap: IAR memory functions are prefixed with "basic_"
|
||||
// - Advanced heap: IAR memory functions are prefixed with "dl"
|
||||
// - No Free heap: IAR memory functions are prefixed with "no_free"
|
||||
//
|
||||
// For No Free heap, IAR does not provide a free and realloc implementation.
|
||||
#if (__VER__ == 8050009)
|
||||
#define STD_LIB_WRAPPER_MALLOC $Sub$$__iar_dlmalloc
|
||||
#define STD_LIB_WRAPPER_FREE $Sub$$__iar_dlfree
|
||||
#define STD_LIB_WRAPPER_CALLOC $Sub$$__iar_dlcalloc
|
||||
#define STD_LIB_WRAPPER_REALLOC $Sub$$__iar_dlrealloc
|
||||
#elif (__VER__ == 9040001)
|
||||
#define STD_LIB_WRAPPER_MALLOC $Sub$$__basic_malloc
|
||||
#define STD_LIB_WRAPPER_FREE $Sub$$__basic_free
|
||||
#define STD_LIB_WRAPPER_CALLOC $Sub$$__basic_calloc
|
||||
#define STD_LIB_WRAPPER_REALLOC $Sub$$__basic_realloc
|
||||
|
||||
#define STD_LIB_WRAPPER_MALLOC_ADVANCED $Sub$$__iar_dlmalloc
|
||||
#define STD_LIB_WRAPPER_FREE_ADVANCED $Sub$$__iar_dlfree
|
||||
#define STD_LIB_WRAPPER_CALLOC_ADVANCED $Sub$$__iar_dlcalloc
|
||||
#define STD_LIB_WRAPPER_REALLOC_ADVANCED $Sub$$__iar_dlrealloc
|
||||
|
||||
#define STD_LIB_WRAPPER_MALLOC_NO_FREE $Sub$$__no_free_malloc
|
||||
#define STD_LIB_WRAPPER_CALLOC_NO_FREE $Sub$$__no_free_calloc
|
||||
#else
|
||||
#error Unsupported IAR compiler version for standard C memory functions retarget
|
||||
#endif
|
||||
|
||||
// Since IAR does not use LTO, resolve the attribute as nothing.
|
||||
#define ATTR_EXT_VIS
|
||||
|
||||
// Since IAR does not use reentrant functions, resolve reentrant parameter to nothing.
|
||||
#define RARG
|
||||
#define VOID_RARG
|
||||
|
||||
#else
|
||||
#error Unsupported compiler for standard C memory functions retarget
|
||||
#endif
|
||||
|
||||
#if defined(TEST_MEMORY_MANAGER_RETARGET_PRESENT)
|
||||
volatile uint32_t retarget_malloc_counter = 0;
|
||||
volatile uint32_t retarget_free_counter = 0;
|
||||
volatile uint32_t retarget_calloc_counter = 0;
|
||||
volatile uint32_t retarget_realloc_counter = 0;
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
************************** GLOBAL FUNCTIONS *******************************
|
||||
******************************************************************************/
|
||||
|
||||
/***************************************************************************//**
|
||||
* malloc() wrapper. Allocates a memory block of at least requested size from
|
||||
* the heap.
|
||||
*
|
||||
* @param[in] size Size of the block, in bytes.
|
||||
*
|
||||
* @return Pointer to allocated block if successful. Null pointer if
|
||||
* allocation failed.
|
||||
*
|
||||
* @note Requesting a block of 0 byte will return a null pointer.
|
||||
*
|
||||
* @note All allocated blocks using this function will be considered long-term
|
||||
* allocations.
|
||||
******************************************************************************/
|
||||
ATTR_EXT_VIS void *STD_LIB_WRAPPER_MALLOC(RARG
|
||||
size_t size)
|
||||
{
|
||||
#if defined(SL_CATALOG_MEMORY_PROFILER_PRESENT)
|
||||
void * volatile return_address = sli_memory_profiler_get_return_address();
|
||||
#endif
|
||||
VOID_RARG;
|
||||
void *ptr;
|
||||
|
||||
ptr = sl_malloc(size);
|
||||
#if defined(TEST_MEMORY_MANAGER_RETARGET_PRESENT)
|
||||
retarget_malloc_counter++;
|
||||
#endif
|
||||
|
||||
#if defined(SL_CATALOG_MEMORY_PROFILER_PRESENT)
|
||||
sli_memory_profiler_track_ownership(SLI_INVALID_MEMORY_TRACKER_HANDLE,
|
||||
ptr,
|
||||
return_address);
|
||||
#endif
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
#if defined(__IAR_SYSTEMS_ICC__) && (__VER__ == 9040001)
|
||||
void *STD_LIB_WRAPPER_MALLOC_ADVANCED(size_t size)
|
||||
{
|
||||
#if defined(SL_CATALOG_MEMORY_PROFILER_PRESENT)
|
||||
void * volatile return_address = sli_memory_profiler_get_return_address();
|
||||
#endif
|
||||
void *ptr;
|
||||
|
||||
ptr = sl_malloc(size);
|
||||
|
||||
#if defined(SL_CATALOG_MEMORY_PROFILER_PRESENT)
|
||||
sli_memory_profiler_track_ownership(SLI_INVALID_MEMORY_TRACKER_HANDLE,
|
||||
ptr,
|
||||
return_address);
|
||||
#endif
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *STD_LIB_WRAPPER_MALLOC_NO_FREE(size_t size)
|
||||
{
|
||||
#if defined(SL_CATALOG_MEMORY_PROFILER_PRESENT)
|
||||
void * volatile return_address = sli_memory_profiler_get_return_address();
|
||||
#endif
|
||||
void *ptr;
|
||||
|
||||
ptr = sl_malloc(size);
|
||||
|
||||
#if defined(SL_CATALOG_MEMORY_PROFILER_PRESENT)
|
||||
sli_memory_profiler_track_ownership(SLI_INVALID_MEMORY_TRACKER_HANDLE,
|
||||
ptr,
|
||||
return_address);
|
||||
#endif
|
||||
|
||||
return ptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
/***************************************************************************//**
|
||||
* free() wrapper. Frees a previously allocated block back into the heap.
|
||||
*
|
||||
* @param[in] ptr Pointer to memory block to be freed.
|
||||
*
|
||||
* @note Passing a null pointer does nothing.
|
||||
******************************************************************************/
|
||||
ATTR_EXT_VIS void STD_LIB_WRAPPER_FREE(RARG
|
||||
void *ptr)
|
||||
{
|
||||
VOID_RARG;
|
||||
sl_free(ptr);
|
||||
#if defined(TEST_MEMORY_MANAGER_RETARGET_PRESENT)
|
||||
retarget_free_counter++;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(__IAR_SYSTEMS_ICC__) && (__VER__ == 9040001)
|
||||
void STD_LIB_WRAPPER_FREE_ADVANCED(void *ptr)
|
||||
{
|
||||
sl_free(ptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
/***************************************************************************//**
|
||||
* calloc() wrapper. Dynamically allocates a block of memory cleared to 0.
|
||||
*
|
||||
* @param[in] item_count Number of elements to be allocated.
|
||||
* @param[in] size Size of each elements, in bytes.
|
||||
*
|
||||
* @return Pointer to allocated block if successful. Null pointer if
|
||||
* allocation failed.
|
||||
*
|
||||
* @note All allocated blocks using this function will be considered long-term
|
||||
* allocations.
|
||||
******************************************************************************/
|
||||
ATTR_EXT_VIS void *STD_LIB_WRAPPER_CALLOC(RARG
|
||||
size_t item_count,
|
||||
size_t size)
|
||||
{
|
||||
#if defined(SL_CATALOG_MEMORY_PROFILER_PRESENT)
|
||||
void * volatile return_address = sli_memory_profiler_get_return_address();
|
||||
#endif
|
||||
VOID_RARG;
|
||||
void *ptr;
|
||||
|
||||
ptr = sl_calloc(item_count, size);
|
||||
#if defined(TEST_MEMORY_MANAGER_RETARGET_PRESENT)
|
||||
retarget_calloc_counter++;
|
||||
#endif
|
||||
|
||||
#if defined(SL_CATALOG_MEMORY_PROFILER_PRESENT)
|
||||
sli_memory_profiler_track_ownership(SLI_INVALID_MEMORY_TRACKER_HANDLE,
|
||||
ptr,
|
||||
return_address);
|
||||
#endif
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
#if defined(__IAR_SYSTEMS_ICC__) && (__VER__ == 9040001)
|
||||
void *STD_LIB_WRAPPER_CALLOC_ADVANCED(size_t item_count,
|
||||
size_t size)
|
||||
{
|
||||
#if defined(SL_CATALOG_MEMORY_PROFILER_PRESENT)
|
||||
void * volatile return_address = sli_memory_profiler_get_return_address();
|
||||
#endif
|
||||
void *ptr;
|
||||
|
||||
ptr = sl_calloc(item_count, size);
|
||||
|
||||
#if defined(SL_CATALOG_MEMORY_PROFILER_PRESENT)
|
||||
sli_memory_profiler_track_ownership(SLI_INVALID_MEMORY_TRACKER_HANDLE,
|
||||
ptr,
|
||||
return_address);
|
||||
#endif
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *STD_LIB_WRAPPER_CALLOC_NO_FREE(size_t item_count,
|
||||
size_t size)
|
||||
{
|
||||
#if defined(SL_CATALOG_MEMORY_PROFILER_PRESENT)
|
||||
void * volatile return_address = sli_memory_profiler_get_return_address();
|
||||
#endif
|
||||
void *ptr;
|
||||
|
||||
ptr = sl_calloc(item_count, size);
|
||||
|
||||
#if defined(SL_CATALOG_MEMORY_PROFILER_PRESENT)
|
||||
sli_memory_profiler_track_ownership(SLI_INVALID_MEMORY_TRACKER_HANDLE,
|
||||
ptr,
|
||||
return_address);
|
||||
#endif
|
||||
|
||||
return ptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
/***************************************************************************//**
|
||||
* realloc() wrapper. Resizes a previously allocated memory block.
|
||||
*
|
||||
* @param[in] ptr Pointer to the allocation to resize. If NULL, behavior
|
||||
* is same as sl_malloc(), sl_memory_alloc().
|
||||
* @param[in] size New size of the block, in bytes. If 0, behavior is same as
|
||||
* sl_free(), sl_memory_free().
|
||||
*
|
||||
* @return Pointer to newly allocated block, if successful. Null pointer if
|
||||
* re-allocation failed.
|
||||
*
|
||||
* @note All re-allocated blocks using this function will be considered
|
||||
* long-term allocations.
|
||||
*
|
||||
* @note 'ptr' NULL and 'size' of 0 bytes is an incorrect parameters
|
||||
* combination. No reallocation will be done by the function as it is
|
||||
* an error condition.
|
||||
*
|
||||
* @note If the new 'size' is the same as the old, the function changes nothing
|
||||
* and returns the same provided address 'ptr'.
|
||||
******************************************************************************/
|
||||
ATTR_EXT_VIS void *STD_LIB_WRAPPER_REALLOC(RARG
|
||||
void *ptr,
|
||||
size_t size)
|
||||
{
|
||||
#if defined(SL_CATALOG_MEMORY_PROFILER_PRESENT)
|
||||
void * volatile return_address = sli_memory_profiler_get_return_address();
|
||||
#endif
|
||||
VOID_RARG;
|
||||
void *r_ptr;
|
||||
|
||||
r_ptr = sl_realloc(ptr, size);
|
||||
#if defined(TEST_MEMORY_MANAGER_RETARGET_PRESENT)
|
||||
retarget_realloc_counter++;
|
||||
#endif
|
||||
|
||||
#if defined(SL_CATALOG_MEMORY_PROFILER_PRESENT)
|
||||
sli_memory_profiler_track_ownership(SLI_INVALID_MEMORY_TRACKER_HANDLE,
|
||||
r_ptr,
|
||||
return_address);
|
||||
#endif
|
||||
|
||||
return r_ptr;
|
||||
}
|
||||
|
||||
#if defined(__IAR_SYSTEMS_ICC__) && (__VER__ == 9040001)
|
||||
void *STD_LIB_WRAPPER_REALLOC_ADVANCED(void *ptr,
|
||||
size_t size)
|
||||
{
|
||||
#if defined(SL_CATALOG_MEMORY_PROFILER_PRESENT)
|
||||
void * volatile return_address = sli_memory_profiler_get_return_address();
|
||||
#endif
|
||||
void *r_ptr;
|
||||
|
||||
r_ptr = sl_realloc(ptr, size);
|
||||
|
||||
#if defined(SL_CATALOG_MEMORY_PROFILER_PRESENT)
|
||||
sli_memory_profiler_track_ownership(SLI_INVALID_MEMORY_TRACKER_HANDLE,
|
||||
r_ptr,
|
||||
return_address);
|
||||
#endif
|
||||
|
||||
return r_ptr;
|
||||
}
|
||||
#endif
|
||||
340
Libs/platform/service/memory_manager/src/sli_memory_manager.h
Normal file
340
Libs/platform/service/memory_manager/src/sli_memory_manager.h
Normal file
@@ -0,0 +1,340 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief Memory Manager Driver API definition.
|
||||
*******************************************************************************
|
||||
* # License
|
||||
* <b>Copyright 2023 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_MEMORY_MANAGER_H_
|
||||
#define SLI_MEMORY_MANAGER_H_
|
||||
|
||||
#include "sl_memory_manager.h"
|
||||
|
||||
#if defined(SL_COMPONENT_CATALOG_PRESENT)
|
||||
#include "sl_component_catalog.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
********************************* DEFINES *********************************
|
||||
******************************************************************************/
|
||||
|
||||
// Memory Manager integration to SystemView is enabled on GCC builds of
|
||||
// applications that include the SystemView component
|
||||
#if defined(SL_CATALOG_SYSTEMVIEW_TRACE_PRESENT) && defined(__GNUC__)
|
||||
#define SLI_MEMORY_MANAGER_ENABLE_SYSTEMVIEW
|
||||
#endif
|
||||
|
||||
// Minimum block alignment in bytes. 8 bytes is the minimum alignment to account for largest CPU data type
|
||||
// that can be used in some block allocation scenarios. 64-bit data type may be used to manipulate the
|
||||
// allocated block. The ARM processor ABI defines data types and byte alignment, and 8-byte alignment
|
||||
// can be seen for the largest data object type.
|
||||
#define SLI_BLOCK_ALLOC_MIN_ALIGN SL_MEMORY_BLOCK_ALIGN_8_BYTES
|
||||
|
||||
// Minimum block allocation size to avoid creating a block too small while splitting up an allocated block.
|
||||
// Minimum size is formed from (metadata + payload) size. Size expressed in bytes.
|
||||
#define SLI_BLOCK_ALLOCATION_MIN_SIZE (SLI_BLOCK_METADATA_SIZE_BYTE + SL_MEMORY_MANAGER_BLOCK_ALLOCATION_MIN_SIZE)
|
||||
|
||||
// Minimum block reservation size to avoid creating a block too small while splitting up a reserved block.
|
||||
// Contrary to block allocations, reservations don't have metadata.
|
||||
#define SLI_BLOCK_RESERVATION_MIN_SIZE_BYTE SL_MEMORY_MANAGER_BLOCK_ALLOCATION_MIN_SIZE
|
||||
#define SLI_BLOCK_RESERVATION_MIN_SIZE_DWORD SLI_BLOCK_LEN_BYTE_TO_DWORD(SL_MEMORY_MANAGER_BLOCK_ALLOCATION_MIN_SIZE)
|
||||
|
||||
// 64-bit word size (in octets).
|
||||
#define SLI_WORD_SIZE_64 8u
|
||||
// 32-bit word size (in octets).
|
||||
#define SLI_WORD_SIZE_32 4u
|
||||
#define SLI_DEF_INT_32_NBR_BITS 32u
|
||||
|
||||
// 1-byte size (in bits).
|
||||
#define SLI_DEF_INT_08_NBR_BITS 8u
|
||||
|
||||
// Size of block metadata area in different units.
|
||||
#define SLI_BLOCK_METADATA_SIZE_BYTE sizeof(sli_block_metadata_t)
|
||||
#define SLI_BLOCK_METADATA_SIZE_DWORD SLI_BLOCK_LEN_BYTE_TO_DWORD(SLI_BLOCK_METADATA_SIZE_BYTE)
|
||||
|
||||
// Size of reservation handle area in different units.
|
||||
#define SLI_RESERVATION_HANDLE_SIZE_BYTE sizeof(sl_memory_reservation_t)
|
||||
#define SLI_RESERVATION_HANDLE_SIZE_DWORD SLI_BLOCK_LEN_BYTE_TO_DWORD(SLI_RESERVATION_HANDLE_SIZE_BYTE)
|
||||
|
||||
// Size of pool handle area in different units.
|
||||
#define SLI_POOL_HANDLE_SIZE_BYTE sizeof(sl_memory_pool_t)
|
||||
#define SLI_POOL_HANDLE_SIZE_DWORD SLI_BLOCK_LEN_BYTE_TO_DWORD(SLI_POOL_HANDLE_SIZE_BYTE)
|
||||
|
||||
#ifdef SLI_MEMORY_MANAGER_ENABLE_TEST_UTILITIES
|
||||
#define SLI_MAX_RESERVATION_COUNT 32
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
********************************** MACROS *********************************
|
||||
******************************************************************************/
|
||||
|
||||
// Macros to align a value to the nearest value multiple of the specified alignment
|
||||
// (rounded up or down). These macros are used for memory addresses requiring an alignment.
|
||||
#define SLI_ALIGN_ROUND_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
|
||||
#define SLI_ALIGN_ROUND_DOWN(num, align) ((num) & ~((align) - 1))
|
||||
|
||||
// Macros to convert block length in different units (bytes, double words).
|
||||
// Byte to word will round up to account for extra bytes.
|
||||
#define SLI_BLOCK_LEN_DWORD_TO_BYTE(len) ((len) * SLI_WORD_SIZE_64)
|
||||
#define SLI_BLOCK_LEN_BYTE_TO_DWORD(len) ((len + SLI_WORD_SIZE_64 - 1) / SLI_WORD_SIZE_64)
|
||||
|
||||
// Macro to test address given a specified data alignment.
|
||||
#define SLI_ADDR_IS_ALIGNED(ptr, align_byte) (((uintptr_t)(const void *)(ptr)) % (align_byte) == 0)
|
||||
|
||||
// Macro to convert from bits to byte.
|
||||
#define SLI_POOL_BITS_TO_BYTE(bits) (((bits) + 7u) / SLI_DEF_INT_08_NBR_BITS)
|
||||
|
||||
/*******************************************************************************
|
||||
********************************* TYPEDEF *********************************
|
||||
******************************************************************************/
|
||||
|
||||
// Block metadata containing information about allocated block.
|
||||
// This metadata allows to implement explicit free blocks list.
|
||||
// NOTE: The metadata size should ideally be a multiple of 8 bytes (see description of
|
||||
// SLI_BLOCK_ALLOC_MIN_ALIGN for other details) or at least multiple of CPU data size
|
||||
// (e.g. 4 bytes for 32-bit CPU).
|
||||
// 'length' is expressed in double words unit. It can described a block up to 512 KB (65535 * 8 bytes).
|
||||
typedef struct {
|
||||
uint16_t block_in_use : 1; // Flag indicating if block allocated or not.
|
||||
uint16_t heap_start_align : 1; // Flag indicating if first block at heap start undergone a data payload adjustment.
|
||||
#if defined(SLI_MEMORY_MANAGER_ENABLE_SYSTEMVIEW)
|
||||
uint16_t block_type : 1; // Block type (LT or ST).
|
||||
uint16_t reserved : 13; // Unallocated for future usage.
|
||||
#else
|
||||
uint16_t reserved : 14; // Unallocated for future usage.
|
||||
#endif
|
||||
uint16_t length; // Block size (metadata not included just data payload), in double words (64 bit).
|
||||
uint16_t offset_neighbour_prev; // Offset to previous neighbor, in double words. It includes metadata/payload sizes.
|
||||
uint16_t offset_neighbour_next; // Offset to next neighbor, in double words.
|
||||
} sli_block_metadata_t;
|
||||
|
||||
/*******************************************************************************
|
||||
**************************** GLOBAL VARIABLES *****************************
|
||||
******************************************************************************/
|
||||
|
||||
extern sli_block_metadata_t *sli_free_st_list_head;
|
||||
extern sli_block_metadata_t *sli_free_lt_list_head;
|
||||
extern uint32_t sli_free_blocks_number;
|
||||
#if defined(DEBUG_EFM) || defined(DEBUG_EFM_USER)
|
||||
extern bool reserve_no_retention_first;
|
||||
#endif
|
||||
|
||||
#ifdef SLI_MEMORY_MANAGER_ENABLE_TEST_UTILITIES
|
||||
extern sl_memory_reservation_t* sli_reservation_handle_ptr_table[];
|
||||
extern uint32_t sli_reservation_alignment_table[];
|
||||
|
||||
extern sl_memory_reservation_t sli_reservation_no_retention_table[];
|
||||
extern uint32_t sli_reservation_no_retention_alignment_table[];
|
||||
#endif
|
||||
|
||||
// The heap name is also used as the Memory Profiler tracker handle for the heap
|
||||
// pool managed by the Memory Manager
|
||||
extern const char sli_mm_heap_name[];
|
||||
extern const char sli_mm_heap_reservation_name[];
|
||||
|
||||
/*******************************************************************************
|
||||
***************************** PROTOTYPES **********************************
|
||||
******************************************************************************/
|
||||
|
||||
/***************************************************************************//**
|
||||
* Initializes a memory block metadata to some reset values.
|
||||
*
|
||||
* @param[in] block_metadata Pointer to block metadata.
|
||||
******************************************************************************/
|
||||
void sli_memory_metadata_init(sli_block_metadata_t *block_metadata);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets pointer to the first free block of adequate size.
|
||||
*
|
||||
* @param[in] size Size of the block, in bytes.
|
||||
* @param[in] align Required alignment for the block, in bytes.
|
||||
* @param[in] type Type of block (long-term or short term).
|
||||
* BLOCK_TYPE_LONG_TERM
|
||||
* BLOCK_TYPE_SHORT_TERM
|
||||
* @param[in] block_reservation Indicates if the free block is for a dynamic
|
||||
* reservation.
|
||||
* @param[out] block Pointer to variable that will receive the
|
||||
* start address of the free block.
|
||||
*
|
||||
* @return Size of the block adjusted with the alignment.
|
||||
******************************************************************************/
|
||||
size_t sli_memory_find_free_block(size_t size,
|
||||
size_t align,
|
||||
sl_memory_block_type_t type,
|
||||
bool block_reservation,
|
||||
sli_block_metadata_t **block);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Finds the next free block that will become the long-term or short-term head
|
||||
* pointer.
|
||||
*
|
||||
* @param[in] type Type of block (long-term or short term).
|
||||
* BLOCK_TYPE_LONG_TERM
|
||||
* BLOCK_TYPE_SHORT_TERM
|
||||
*
|
||||
* @param[in] block_start_from Pointer to block where to start searching.
|
||||
* NULL pointer means start from one of heap
|
||||
* ends according to the block type.
|
||||
*
|
||||
* @return Pointer to the new free block.
|
||||
******************************************************************************/
|
||||
sli_block_metadata_t *sli_memory_find_head_free_block(sl_memory_block_type_t type,
|
||||
sli_block_metadata_t *block_start_from);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets long-term head pointer to the first free block.
|
||||
*
|
||||
* @return Pointer to first free long-term block.
|
||||
******************************************************************************/
|
||||
void *sli_memory_get_longterm_head_ptr(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets short-term head pointer to the first free block.
|
||||
*
|
||||
* @return Pointer to first free short-term block.
|
||||
******************************************************************************/
|
||||
void *sli_memory_get_shortterm_head_ptr(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Update free lists heads (short and long terms)
|
||||
*
|
||||
* @param[in] free_head Block from where to start searching or next free block.
|
||||
*
|
||||
* @param[in] condition_block Block condition to check if update is necessary
|
||||
* or not.
|
||||
*
|
||||
* @param[in] search Boolean condition to check if searching the heap for a free
|
||||
* block is necessary.
|
||||
******************************************************************************/
|
||||
void sli_update_free_list_heads(sli_block_metadata_t *free_head,
|
||||
const sli_block_metadata_t *condition_block,
|
||||
bool search);
|
||||
|
||||
#ifdef SLI_MEMORY_MANAGER_ENABLE_TEST_UTILITIES
|
||||
/***************************************************************************//**
|
||||
* Gets the pointer to sl_memory_reservation_t{} by block address.
|
||||
*
|
||||
* @param[in] addr Pointer to the block reservation.
|
||||
*
|
||||
* @return Pointer to reservation handle.
|
||||
******************************************************************************/
|
||||
sl_memory_reservation_t *sli_memory_get_reservation_handle_by_addr(void *addr);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets the size of a reservation by block address.
|
||||
*
|
||||
* @param[in] addr Pointer to the block reservation.
|
||||
*
|
||||
* @return Size of the reservation in bytes.
|
||||
******************************************************************************/
|
||||
uint32_t sli_memory_get_reservation_size_by_addr(void *addr);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Get the alignment of a reservation by block address.
|
||||
*
|
||||
* @param[in] addr Pointer to the block reservation.
|
||||
*
|
||||
* @return Alignment of the reservation in bytes.
|
||||
******************************************************************************/
|
||||
uint32_t sli_memory_get_reservation_align_by_addr(void *addr);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Bookkeeps a reservation for profiling purposes.
|
||||
*
|
||||
* @param[in] reservation_handle_ptr Pointer to the reservation handle.
|
||||
* @param[in] align Alignment of the reservation.
|
||||
*
|
||||
* @return SL_STATUS_FULL if record is full.
|
||||
******************************************************************************/
|
||||
sl_status_t sli_memory_save_reservation_handle(sl_memory_reservation_t *reservation_handle_ptr,
|
||||
uint32_t align);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Removes a reservation from records.
|
||||
*
|
||||
* @param[in] reservation_handle_ptr Pointer to the reservation handle.
|
||||
*
|
||||
* @return SL_STATUS_NOT_FOUND if reservation is does not exist in records.
|
||||
******************************************************************************/
|
||||
sl_status_t sli_memory_remove_reservation_handle(sl_memory_reservation_t *reservation_handle_ptr);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Bookkeeps a reservation (no retention) for profiling purposes.
|
||||
*
|
||||
* @param[in] block_address Pointer to the block reservation.
|
||||
* @param[in] block_size Size of the reservation.
|
||||
* @param[in] align Alignment of the reservation.
|
||||
*
|
||||
* @return SL_STATUS_NOT_FOUND if reservation is does not exist in records.
|
||||
******************************************************************************/
|
||||
sl_status_t sli_memory_save_reservation_no_retention(void * block_address, uint32_t block_size, uint32_t align);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets the size of a reservation (no retention) by block address.
|
||||
*
|
||||
* @param[in] addr Pointer to the block reservation.
|
||||
*
|
||||
* @return Size of the reservation (no retention) in bytes.
|
||||
******************************************************************************/
|
||||
uint32_t sli_memory_get_reservation_no_retention_size(void * addr);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets the alignment of a reservation (no retention) by block address.
|
||||
*
|
||||
* @param[in] addr Pointer to the block reservation.
|
||||
*
|
||||
* @return Alignment of the reservation in bytes.
|
||||
******************************************************************************/
|
||||
uint32_t sli_memory_get_reservation_no_retention_align(void * addr);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Does a heap integrity check forwards from sli_free_lt_list_head and return
|
||||
* the pointer to the corrupted sli_block_metadata_t{} (if applicable).
|
||||
* This could go past reservations so there are checks.
|
||||
*
|
||||
* @return Pointer to the corrupted sli_block_metadata_t{}.
|
||||
******************************************************************************/
|
||||
sli_block_metadata_t * sli_memory_check_heap_integrity_forwards(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Does a heap integrity check backwards from sli_free_st_list_head and return
|
||||
* the pointer to the corrupted sli_block_metadata_t{} (if applicable).
|
||||
* This should not go past any reservations, hence there are no checks.
|
||||
*
|
||||
* @return Pointer to the corrupted sli_block_metadata_t{}.
|
||||
******************************************************************************/
|
||||
sli_block_metadata_t *sli_memory_check_heap_integrity_backwards(void);
|
||||
#endif /* SLI_MEMORY_MANAGER_ENABLE_TEST_UTILITIES */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SLI_MEMORY_MANAGER_H_ */
|
||||
@@ -0,0 +1,712 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief Memory Manager Driver Implementation.
|
||||
*******************************************************************************
|
||||
* # License
|
||||
* <b>Copyright 2023 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 <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdalign.h>
|
||||
|
||||
#include "sl_memory_manager_config.h"
|
||||
#include "sl_memory_manager.h"
|
||||
#include "sli_memory_manager.h"
|
||||
#include "sl_assert.h"
|
||||
#include "sl_bit.h"
|
||||
#include "sl_common.h"
|
||||
|
||||
#if defined(SL_COMPONENT_CATALOG_PRESENT)
|
||||
#include "sl_component_catalog.h"
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
********************************* DEFINES *********************************
|
||||
******************************************************************************/
|
||||
|
||||
// Minimum block alignment in bytes. 8 bytes is the minimum alignment to account for largest CPU data type
|
||||
// that can be used in some block allocation scenarios. 64-bit data type may be used to manipulate the
|
||||
// allocated block. The ARM processor ABI defines data types and byte alignment, and 8-byte alignment
|
||||
// can be seen for the largest data object type.
|
||||
#define SLI_BLOCK_ALLOC_MIN_ALIGN SL_MEMORY_BLOCK_ALIGN_8_BYTES
|
||||
|
||||
// Minimum block allocation size to avoid creating a block too small while splitting up an allocated block.
|
||||
// Minimum size is formed from (metadata + payload) size. Size expressed in bytes.
|
||||
#define SLI_BLOCK_ALLOCATION_MIN_SIZE (SLI_BLOCK_METADATA_SIZE_BYTE + SL_MEMORY_MANAGER_BLOCK_ALLOCATION_MIN_SIZE)
|
||||
|
||||
// 64-bit word size (in octets).
|
||||
#define SLI_WORD_SIZE_64 8u
|
||||
|
||||
// Size of metadata area in different units.
|
||||
#define SLI_BLOCK_METADATA_SIZE_BYTE sizeof(sli_block_metadata_t)
|
||||
#define SLI_BLOCK_METADATA_SIZE_DWORD SLI_BLOCK_LEN_BYTE_TO_DWORD(SLI_BLOCK_METADATA_SIZE_BYTE)
|
||||
|
||||
/*******************************************************************************
|
||||
*************************** LOCAL VARIABLES ********************************
|
||||
******************************************************************************/
|
||||
|
||||
sli_block_metadata_t *sli_free_lt_list_head;
|
||||
sli_block_metadata_t *sli_free_st_list_head;
|
||||
uint32_t sli_free_blocks_number;
|
||||
|
||||
#ifdef SLI_MEMORY_MANAGER_ENABLE_TEST_UTILITIES
|
||||
// Dynamic reservation bookkeeping.
|
||||
sl_memory_reservation_t *sli_reservation_handle_ptr_table[SLI_MAX_RESERVATION_COUNT] = { NULL };
|
||||
uint32_t sli_reservation_alignment_table[SLI_MAX_RESERVATION_COUNT] = { 0 };
|
||||
|
||||
// Reservation no retention bookkeeping.
|
||||
// Array of structs instead of pointers to avoid dynamic allocation for handle.
|
||||
sl_memory_reservation_t sli_reservation_no_retention_table[SLI_MAX_RESERVATION_COUNT] = { 0 };
|
||||
uint32_t sli_reservation_no_retention_alignment_table[SLI_MAX_RESERVATION_COUNT] = { 0 };
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
*************************** LOCAL FUNCTIONS *******************************
|
||||
******************************************************************************/
|
||||
|
||||
#ifdef SLI_MEMORY_MANAGER_ENABLE_TEST_UTILITIES
|
||||
/***************************************************************************//**
|
||||
* Gets the index in sli_reservation_handle_ptr_table[] by block address.
|
||||
*
|
||||
* @param[in] addr Pointer to block reservation.
|
||||
*
|
||||
* @return Corresponding index in sli_reservation_handle_ptr_table.
|
||||
******************************************************************************/
|
||||
static uint32_t get_reservation_ix_by_addr(void *addr)
|
||||
{
|
||||
for (uint32_t ix = 0; ix < SLI_MAX_RESERVATION_COUNT; ix++) {
|
||||
if (sli_reservation_handle_ptr_table[ix] == NULL) {
|
||||
continue;
|
||||
}
|
||||
if (sli_reservation_handle_ptr_table[ix]->block_address == addr) {
|
||||
return ix;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets the index in sli_reservation_handle_ptr_table[]
|
||||
* by reservation handle pointer.
|
||||
*
|
||||
* @param[in] reservation_handle_ptr Pointer to reservation handle.
|
||||
*
|
||||
* @return Corresponding index in sli_reservation_handle_ptr_table.
|
||||
******************************************************************************/
|
||||
static uint32_t get_reservation_ix_by_handle(sl_memory_reservation_t *reservation_handle_ptr)
|
||||
{
|
||||
for (uint32_t ix = 0; ix < SLI_MAX_RESERVATION_COUNT; ix++) {
|
||||
if (sli_reservation_handle_ptr_table[ix] == NULL) {
|
||||
continue;
|
||||
}
|
||||
if (sli_reservation_handle_ptr_table[ix] == reservation_handle_ptr) {
|
||||
return ix;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Get an index of sli_reservation_handle_ptr_table that is free.
|
||||
*
|
||||
* @return Index of an empty entry in sli_reservation_handle_ptr_table.
|
||||
******************************************************************************/
|
||||
static uint32_t get_available_reservation_handle_ix(void)
|
||||
{
|
||||
for (uint32_t ix = 0; ix < SLI_MAX_RESERVATION_COUNT; ix++) {
|
||||
if (sli_reservation_handle_ptr_table[ix] == NULL) {
|
||||
return ix;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets the index in sli_reservation_no_retention_table[] by block address.
|
||||
*
|
||||
* @param[in] addr Pointer to block reservation.
|
||||
*
|
||||
* @return Corresponding index in sli_reservation_no_retention_table[].
|
||||
******************************************************************************/
|
||||
static uint32_t get_reservation_no_retention_ix(void *addr)
|
||||
{
|
||||
for (uint32_t ix = 0; ix < SLI_MAX_RESERVATION_COUNT; ix++) {
|
||||
if (sli_reservation_no_retention_table[ix].block_address == NULL) {
|
||||
continue;
|
||||
}
|
||||
if (sli_reservation_no_retention_table[ix].block_address == addr) {
|
||||
return ix;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets an index of sli_reservation_no_retention_table[] that is free.
|
||||
*
|
||||
* @return Index of an empty entry in sli_reservation_no_retention_table[].
|
||||
******************************************************************************/
|
||||
static uint32_t get_available_reservation_no_retention_ix(void)
|
||||
{
|
||||
for (uint32_t ix = 0; ix < SLI_MAX_RESERVATION_COUNT; ix++) {
|
||||
if (sli_reservation_no_retention_table[ix].block_address == NULL) {
|
||||
return ix;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/***************************************************************************//**
|
||||
* Initializes a memory block metadata to some reset values.
|
||||
******************************************************************************/
|
||||
void sli_memory_metadata_init(sli_block_metadata_t *block_metadata)
|
||||
{
|
||||
block_metadata->block_in_use = 0;
|
||||
block_metadata->heap_start_align = 0;
|
||||
block_metadata->reserved = 0;
|
||||
block_metadata->length = 0;
|
||||
block_metadata->offset_neighbour_prev = 0;
|
||||
block_metadata->offset_neighbour_next = 0;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets pointer pointing to the first free block of adequate size.
|
||||
*
|
||||
* @note (1) For a block reservation, there's no metadata next to the
|
||||
* reserved block. For this reason, when looking for a free block
|
||||
* large enough to fit a new reserved block, the size of the metadata
|
||||
* is counted in the available size of the free blocks.
|
||||
*
|
||||
* @note (2) For a short-term block, if the required data alignment is greater
|
||||
* than 8 bytes, the found block size must account for the correct
|
||||
* alignment of the block data payload. A series of computations is
|
||||
* done starting from the end of the found block to determine the
|
||||
* best data offset needed to align the data payload. The worst
|
||||
* alignment (size_real + block_align) cannot be taken by default
|
||||
* as it may imply loosing too many bytes in internal fragmentation
|
||||
* due to the alignment requirement.
|
||||
******************************************************************************/
|
||||
size_t sli_memory_find_free_block(size_t size,
|
||||
size_t align,
|
||||
sl_memory_block_type_t type,
|
||||
bool block_reservation,
|
||||
sli_block_metadata_t **block)
|
||||
{
|
||||
sli_block_metadata_t *current_block_metadata = NULL;
|
||||
void *data_payload = NULL;
|
||||
size_t size_adjusted = 0;
|
||||
size_t current_block_len;
|
||||
size_t block_align = (align == SL_MEMORY_BLOCK_ALIGN_DEFAULT) ? SLI_BLOCK_ALLOC_MIN_ALIGN : align;
|
||||
size_t data_payload_offset;
|
||||
bool is_aligned = false;
|
||||
|
||||
*block = NULL;
|
||||
|
||||
current_block_metadata = (type == BLOCK_TYPE_LONG_TERM) ? sli_free_lt_list_head : sli_free_st_list_head;
|
||||
if (current_block_metadata == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
current_block_len = SLI_BLOCK_LEN_DWORD_TO_BYTE(current_block_metadata->length);
|
||||
|
||||
// For a block reservation, add the metadata's size to the free blocks' available memory space. See Note #2.
|
||||
current_block_len += block_reservation ? SLI_BLOCK_METADATA_SIZE_BYTE : 0;
|
||||
|
||||
// Try to find a block to allocate (first-fit).
|
||||
while (current_block_metadata != NULL) {
|
||||
if ((!current_block_metadata->block_in_use) && (current_block_len >= size)) {
|
||||
if (type == BLOCK_TYPE_LONG_TERM) {
|
||||
// Check alignment requested and ensure size of found block can accommodate worst case alignment.
|
||||
// For LT, alignment requirement can be verified here whether the block is split or not.
|
||||
data_payload = (void *)((uint8_t *)current_block_metadata + SLI_BLOCK_METADATA_SIZE_BYTE);
|
||||
is_aligned = SLI_ADDR_IS_ALIGNED(data_payload, block_align);
|
||||
data_payload_offset = (uintptr_t)data_payload % block_align;
|
||||
|
||||
if (is_aligned || (current_block_len >= (size + data_payload_offset))) {
|
||||
// Compute remaining block size given an alignment handling or not.
|
||||
size_adjusted = is_aligned ? size : (size + data_payload_offset);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (block_align == SLI_BLOCK_ALLOC_MIN_ALIGN) {
|
||||
// If alignment is 8 bytes (default min alignment), take the requested adjusted size.
|
||||
size_adjusted = size;
|
||||
} else {
|
||||
// If non 8-byte alignment, search the more optimized size accounting for the required alignment. See Note #3.
|
||||
uint8_t *block_end = (uint8_t *)((uint64_t *)current_block_metadata + SLI_BLOCK_METADATA_SIZE_DWORD + current_block_metadata->length);
|
||||
|
||||
data_payload = (void *)(block_end - size);
|
||||
data_payload = (void *)SLI_ALIGN_ROUND_DOWN(((uintptr_t)data_payload), block_align);
|
||||
size_adjusted = (size_t)(block_end - (uint8_t *)data_payload);
|
||||
}
|
||||
|
||||
if (current_block_len >= size_adjusted) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get next block.
|
||||
if (type == BLOCK_TYPE_LONG_TERM) {
|
||||
if (current_block_metadata->offset_neighbour_next == 0) {
|
||||
return 0; // End of heap. No block found.
|
||||
}
|
||||
// Long-term browsing direction goes from start to end of heap.
|
||||
current_block_metadata = (sli_block_metadata_t *)((uint64_t *)current_block_metadata + (current_block_metadata->offset_neighbour_next));
|
||||
} else {
|
||||
if (current_block_metadata->offset_neighbour_prev == 0) {
|
||||
return 0; // Start of heap. No block found.
|
||||
}
|
||||
// Short-term browsing direction goes from end to start of heap.
|
||||
current_block_metadata = (sli_block_metadata_t *)((uint64_t *)current_block_metadata - (current_block_metadata->offset_neighbour_prev));
|
||||
}
|
||||
|
||||
current_block_len = SLI_BLOCK_LEN_DWORD_TO_BYTE(current_block_metadata->length);
|
||||
current_block_len += block_reservation ? SLI_BLOCK_METADATA_SIZE_BYTE : 0;
|
||||
}
|
||||
|
||||
*block = current_block_metadata;
|
||||
return size_adjusted;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Finds the next free block that will become the long-term or short-term head
|
||||
* pointer.
|
||||
******************************************************************************/
|
||||
sli_block_metadata_t *sli_memory_find_head_free_block(sl_memory_block_type_t type,
|
||||
sli_block_metadata_t *block_start_from)
|
||||
{
|
||||
sli_block_metadata_t *current_block_metadata = NULL;
|
||||
sli_block_metadata_t *free_block_metadata = NULL;
|
||||
bool search = true;
|
||||
|
||||
if (sli_free_blocks_number == 0) {
|
||||
// No more free blocks.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (block_start_from != NULL) {
|
||||
// Start searching from the given block.
|
||||
current_block_metadata = block_start_from;
|
||||
} else {
|
||||
// Start searching from heap start (long-term [LT]) or near heap end (short-term [ST]).
|
||||
// For ST, searching cannot start at the absolute heap end. So the ST head pointer is used as it points
|
||||
// to the last free block closest to the heap end.
|
||||
sl_memory_region_t heap_region = sl_memory_get_heap_region();
|
||||
|
||||
current_block_metadata = (type == BLOCK_TYPE_LONG_TERM) ? (sli_block_metadata_t *)heap_region.addr : sli_free_st_list_head;
|
||||
}
|
||||
|
||||
// Long-term block: find the first free block closest to the heap start.
|
||||
// Short-term block: find the first free block closest to the heap end.
|
||||
do {
|
||||
if (current_block_metadata->block_in_use == 0) {
|
||||
free_block_metadata = current_block_metadata;
|
||||
search = false;
|
||||
} else if ((type == BLOCK_TYPE_LONG_TERM) && (current_block_metadata->offset_neighbour_next != 0)) {
|
||||
current_block_metadata = (sli_block_metadata_t *)((uint64_t *)current_block_metadata + (current_block_metadata->offset_neighbour_next));
|
||||
} else if ((type == BLOCK_TYPE_SHORT_TERM) && (current_block_metadata->offset_neighbour_prev != 0)) {
|
||||
current_block_metadata = (sli_block_metadata_t *)((uint64_t *)current_block_metadata - (current_block_metadata->offset_neighbour_prev));
|
||||
} else {
|
||||
free_block_metadata = NULL;
|
||||
break;
|
||||
}
|
||||
} while (search);
|
||||
|
||||
return free_block_metadata;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets long-term head pointer pointing to the first free block.
|
||||
******************************************************************************/
|
||||
void *sli_memory_get_longterm_head_ptr(void)
|
||||
{
|
||||
return (void *)sli_free_lt_list_head;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets short-term head pointer pointing to the first free block.
|
||||
******************************************************************************/
|
||||
void *sli_memory_get_shortterm_head_ptr(void)
|
||||
{
|
||||
return (void *)sli_free_st_list_head;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Update free lists heads (short and long terms).
|
||||
******************************************************************************/
|
||||
void sli_update_free_list_heads(sli_block_metadata_t *free_head,
|
||||
const sli_block_metadata_t *condition_block,
|
||||
bool search)
|
||||
{
|
||||
if (search) {
|
||||
if ((sli_free_lt_list_head == condition_block) || (condition_block == NULL)) {
|
||||
sli_free_lt_list_head = sli_memory_find_head_free_block(BLOCK_TYPE_LONG_TERM, free_head);
|
||||
}
|
||||
if ((sli_free_st_list_head == condition_block) || (condition_block == NULL)) {
|
||||
sli_free_st_list_head = sli_memory_find_head_free_block(BLOCK_TYPE_SHORT_TERM, free_head);
|
||||
}
|
||||
} else {
|
||||
if (sli_free_lt_list_head == condition_block) {
|
||||
sli_free_lt_list_head = free_head;
|
||||
} else if (free_head < sli_free_lt_list_head) {
|
||||
sli_free_lt_list_head = free_head;
|
||||
}
|
||||
if (sli_free_st_list_head == condition_block) {
|
||||
sli_free_st_list_head = free_head;
|
||||
} else if (free_head > sli_free_st_list_head) {
|
||||
sli_free_st_list_head = free_head;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SLI_MEMORY_MANAGER_ENABLE_TEST_UTILITIES
|
||||
/***************************************************************************//**
|
||||
* Gets the pointer to sl_memory_reservation_t{} by block address.
|
||||
******************************************************************************/
|
||||
sl_memory_reservation_t *sli_memory_get_reservation_handle_by_addr(void *addr)
|
||||
{
|
||||
uint32_t reservation_ix;
|
||||
reservation_ix = get_reservation_ix_by_addr(addr);
|
||||
|
||||
if (reservation_ix != (uint32_t)-1) {
|
||||
return sli_reservation_handle_ptr_table[reservation_ix];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets the size of a reservation by block address.
|
||||
******************************************************************************/
|
||||
uint32_t sli_memory_get_reservation_size_by_addr(void *addr)
|
||||
{
|
||||
sl_memory_reservation_t * reservation_handle_ptr;
|
||||
reservation_handle_ptr = sli_memory_get_reservation_handle_by_addr(addr);
|
||||
|
||||
if (reservation_handle_ptr != NULL) {
|
||||
return reservation_handle_ptr->block_size;
|
||||
}
|
||||
// Not a reservation, return 0 size.
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets the alignment of a reservation by block address.
|
||||
******************************************************************************/
|
||||
uint32_t sli_memory_get_reservation_align_by_addr(void *addr)
|
||||
{
|
||||
uint32_t reservation_ix = -1;
|
||||
reservation_ix = get_reservation_ix_by_addr(addr);
|
||||
|
||||
if (reservation_ix != (uint32_t)-1) {
|
||||
return sli_reservation_alignment_table[reservation_ix];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Bookkeeps a reservation for profiling purposes.
|
||||
******************************************************************************/
|
||||
sl_status_t sli_memory_save_reservation_handle(sl_memory_reservation_t *reservation_handle_ptr,
|
||||
uint32_t align)
|
||||
{
|
||||
uint32_t reservation_ix = -1;
|
||||
reservation_ix = get_available_reservation_handle_ix();
|
||||
|
||||
if (reservation_ix != (uint32_t)-1) {
|
||||
sli_reservation_handle_ptr_table[reservation_ix] = reservation_handle_ptr;
|
||||
sli_reservation_alignment_table[reservation_ix] = align;
|
||||
return SL_STATUS_OK;
|
||||
} else {
|
||||
return SL_STATUS_FULL;
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Removes a reservation from records.
|
||||
******************************************************************************/
|
||||
sl_status_t sli_memory_remove_reservation_handle(sl_memory_reservation_t *reservation_handle_ptr)
|
||||
{
|
||||
uint32_t reservation_ix = -1;
|
||||
reservation_ix = get_reservation_ix_by_handle(reservation_handle_ptr);
|
||||
|
||||
if (reservation_ix != (uint32_t)-1) {
|
||||
sli_reservation_handle_ptr_table[reservation_ix] = NULL;
|
||||
sli_reservation_alignment_table[reservation_ix] = 0;
|
||||
return SL_STATUS_OK;
|
||||
} else {
|
||||
return SL_STATUS_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Bookkeeps a reservation (no retention) for profiling purposes.
|
||||
******************************************************************************/
|
||||
sl_status_t sli_memory_save_reservation_no_retention(void * block_address, uint32_t block_size, uint32_t align)
|
||||
{
|
||||
uint32_t reservation_ix = -1;
|
||||
reservation_ix = get_available_reservation_no_retention_ix();
|
||||
|
||||
if (reservation_ix != (uint32_t)-1) {
|
||||
sli_reservation_no_retention_table[reservation_ix].block_address = block_address;
|
||||
sli_reservation_no_retention_table[reservation_ix].block_size = block_size;
|
||||
sli_reservation_no_retention_alignment_table[reservation_ix] = align;
|
||||
|
||||
return SL_STATUS_OK;
|
||||
} else {
|
||||
return SL_STATUS_FULL;
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets the size of a reservation (no retention) by block address.
|
||||
******************************************************************************/
|
||||
uint32_t sli_memory_get_reservation_no_retention_size(void * addr)
|
||||
{
|
||||
uint32_t reservation_ix = -1;
|
||||
reservation_ix = get_reservation_no_retention_ix(addr);
|
||||
|
||||
if (reservation_ix != (uint32_t)-1) {
|
||||
return sli_reservation_no_retention_table[reservation_ix].block_size;
|
||||
}
|
||||
// Not a reservation (no retention), return 0 size.
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets the alignment of a reservation (no retention) by block address.
|
||||
******************************************************************************/
|
||||
uint32_t sli_memory_get_reservation_no_retention_align(void * addr)
|
||||
{
|
||||
uint32_t reservation_ix = -1;
|
||||
reservation_ix = get_reservation_no_retention_ix(addr);
|
||||
|
||||
if (reservation_ix != (uint32_t)-1) {
|
||||
return sli_reservation_no_retention_alignment_table[reservation_ix];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Does a heap integrity check forwards from sli_free_lt_list_head and return
|
||||
* the pointer to the corrupted sli_block_metadata_t{} (if applicable).
|
||||
* This could go past reservations so there are checks.
|
||||
******************************************************************************/
|
||||
sli_block_metadata_t *sli_memory_check_heap_integrity_forwards(void)
|
||||
{
|
||||
uint64_t * heap_end_by_metadata = 0;
|
||||
uint32_t is_corrupted = 0;
|
||||
uint32_t reservation_size;
|
||||
uint32_t reservation_size_real;
|
||||
uint32_t alignment;
|
||||
sli_block_metadata_t* current = sli_free_lt_list_head;
|
||||
sl_memory_region_t heap_region;
|
||||
heap_region = sl_memory_get_heap_region();
|
||||
|
||||
while (current != NULL) {
|
||||
// Reached last block in heap.
|
||||
if (current->offset_neighbour_next == 0) {
|
||||
heap_end_by_metadata = ((uint64_t *)current + (current->length + SLI_BLOCK_METADATA_SIZE_DWORD));
|
||||
|
||||
// Check if reservation (one or more).
|
||||
alignment = sli_memory_get_reservation_align_by_addr((void *)heap_end_by_metadata);
|
||||
reservation_size = sli_memory_get_reservation_size_by_addr((void *)heap_end_by_metadata);
|
||||
if (alignment == SL_MEMORY_BLOCK_ALIGN_DEFAULT) {
|
||||
reservation_size_real = reservation_size;
|
||||
} else {
|
||||
reservation_size_real = SLI_ALIGN_ROUND_UP(reservation_size, alignment);
|
||||
}
|
||||
|
||||
while (reservation_size != 0) {
|
||||
heap_end_by_metadata = (uint64_t *)((uint8_t*)heap_end_by_metadata + reservation_size_real);
|
||||
alignment = sli_memory_get_reservation_align_by_addr((void *)heap_end_by_metadata);
|
||||
reservation_size = sli_memory_get_reservation_size_by_addr((void *)heap_end_by_metadata);
|
||||
if (alignment == SL_MEMORY_BLOCK_ALIGN_DEFAULT) {
|
||||
reservation_size_real = reservation_size;
|
||||
} else {
|
||||
reservation_size_real = SLI_ALIGN_ROUND_UP(reservation_size, alignment);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if reservation no retention (one or more).
|
||||
// Only needed for forwards.
|
||||
alignment = sli_memory_get_reservation_no_retention_align((void *)heap_end_by_metadata);
|
||||
reservation_size = sli_memory_get_reservation_no_retention_size((void *)heap_end_by_metadata);
|
||||
if (alignment == SL_MEMORY_BLOCK_ALIGN_DEFAULT) {
|
||||
reservation_size_real = reservation_size;
|
||||
} else {
|
||||
reservation_size_real = SLI_ALIGN_ROUND_UP(reservation_size, alignment);
|
||||
}
|
||||
|
||||
while (reservation_size != 0) {
|
||||
heap_end_by_metadata = (uint64_t *)((uint8_t*)heap_end_by_metadata + reservation_size_real);
|
||||
alignment = sli_memory_get_reservation_no_retention_align((void *)heap_end_by_metadata);
|
||||
reservation_size = sli_memory_get_reservation_no_retention_size((void *)heap_end_by_metadata);
|
||||
if (alignment == SL_MEMORY_BLOCK_ALIGN_DEFAULT) {
|
||||
reservation_size_real = reservation_size;
|
||||
} else {
|
||||
reservation_size_real = SLI_ALIGN_ROUND_UP(reservation_size, alignment);
|
||||
}
|
||||
}
|
||||
|
||||
if (heap_end_by_metadata != (void *)((uintptr_t)heap_region.addr + heap_region.size)) {
|
||||
is_corrupted = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Calculate the address of the next block using offset and length.
|
||||
sli_block_metadata_t *next_blk_by_offset = (sli_block_metadata_t *)((uint64_t *)current + (current->offset_neighbour_next));
|
||||
sli_block_metadata_t *next_blk_by_len = (sli_block_metadata_t *)((uint64_t *)current + (current->length + SLI_BLOCK_METADATA_SIZE_DWORD));
|
||||
|
||||
// Check if reservation (one or more).
|
||||
alignment = sli_memory_get_reservation_align_by_addr((void *)next_blk_by_len);
|
||||
reservation_size = sli_memory_get_reservation_size_by_addr((void *)next_blk_by_len);
|
||||
if (alignment == SL_MEMORY_BLOCK_ALIGN_DEFAULT) {
|
||||
reservation_size_real = reservation_size;
|
||||
} else {
|
||||
reservation_size_real = SLI_ALIGN_ROUND_UP(reservation_size, alignment);
|
||||
}
|
||||
|
||||
while (reservation_size != 0) {
|
||||
next_blk_by_len = (sli_block_metadata_t *)((uint8_t*)next_blk_by_len + reservation_size_real);
|
||||
alignment = sli_memory_get_reservation_align_by_addr((void *)next_blk_by_len);
|
||||
reservation_size = sli_memory_get_reservation_size_by_addr((void *)next_blk_by_len);
|
||||
if (alignment == SL_MEMORY_BLOCK_ALIGN_DEFAULT) {
|
||||
reservation_size_real = reservation_size;
|
||||
} else {
|
||||
reservation_size_real = SLI_ALIGN_ROUND_UP(reservation_size, alignment);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if reservation no retention (one or more).
|
||||
// Only needed for forwards.
|
||||
alignment = sli_memory_get_reservation_no_retention_align((void *)next_blk_by_len);
|
||||
reservation_size = sli_memory_get_reservation_no_retention_size((void *)next_blk_by_len);
|
||||
if (alignment == SL_MEMORY_BLOCK_ALIGN_DEFAULT) {
|
||||
reservation_size_real = reservation_size;
|
||||
} else {
|
||||
reservation_size_real = SLI_ALIGN_ROUND_UP(reservation_size, alignment);
|
||||
}
|
||||
|
||||
while (reservation_size != 0) {
|
||||
next_blk_by_len = (sli_block_metadata_t *)((uint8_t*)next_blk_by_len + reservation_size_real);
|
||||
alignment = sli_memory_get_reservation_no_retention_align((void *)next_blk_by_len);
|
||||
reservation_size = sli_memory_get_reservation_no_retention_size((void *)next_blk_by_len);
|
||||
if (alignment == SL_MEMORY_BLOCK_ALIGN_DEFAULT) {
|
||||
reservation_size_real = reservation_size;
|
||||
} else {
|
||||
reservation_size_real = SLI_ALIGN_ROUND_UP(reservation_size, alignment);
|
||||
}
|
||||
}
|
||||
|
||||
if (next_blk_by_offset != next_blk_by_len) {
|
||||
is_corrupted = 1;
|
||||
break;
|
||||
} else {
|
||||
current = next_blk_by_offset;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_corrupted) {
|
||||
return (sli_block_metadata_t *)current;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Does a heap integrity check backwards from sli_free_st_list_head and return
|
||||
* the pointer to the corrupted sli_block_metadata_t{} (if applicable).
|
||||
* This should not go past any reservations, hence there are no checks.
|
||||
******************************************************************************/
|
||||
sli_block_metadata_t *sli_memory_check_heap_integrity_backwards(void)
|
||||
{
|
||||
uint64_t * heap_base_by_metadata = 0;
|
||||
uint32_t is_corrupted = 0;
|
||||
uint32_t reservation_size;
|
||||
uint32_t reservation_size_real;
|
||||
uint32_t alignment;
|
||||
sli_block_metadata_t* current = sli_free_st_list_head;
|
||||
sl_memory_region_t heap_region;
|
||||
heap_region = sl_memory_get_heap_region();
|
||||
|
||||
while (current != NULL) {
|
||||
// Reached first block in heap.
|
||||
if (current->offset_neighbour_prev == 0) {
|
||||
heap_base_by_metadata = ((uint64_t *)current);
|
||||
if (heap_base_by_metadata != (void *)heap_region.addr) {
|
||||
is_corrupted = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Calculate the address of the current block using offset and length of the previous block.
|
||||
sli_block_metadata_t *prev_blk_by_offset = (sli_block_metadata_t *)((uint64_t *)current - (current->offset_neighbour_prev));
|
||||
sli_block_metadata_t *current_by_prev_offset = (sli_block_metadata_t *)((uint64_t *)prev_blk_by_offset + (prev_blk_by_offset->offset_neighbour_next));
|
||||
sli_block_metadata_t *current_by_prev_len = (sli_block_metadata_t *)((uint64_t *)prev_blk_by_offset + (prev_blk_by_offset->length + SLI_BLOCK_METADATA_SIZE_DWORD));
|
||||
|
||||
// Check if reservation (one or more).
|
||||
// This is required when sli_free_st_list_head has reservations before it.
|
||||
alignment = sli_memory_get_reservation_align_by_addr((void *)current_by_prev_len);
|
||||
reservation_size = sli_memory_get_reservation_size_by_addr((void *)current_by_prev_len);
|
||||
if (alignment == SL_MEMORY_BLOCK_ALIGN_DEFAULT) {
|
||||
reservation_size_real = reservation_size;
|
||||
} else {
|
||||
reservation_size_real = SLI_ALIGN_ROUND_UP(reservation_size, alignment);
|
||||
}
|
||||
|
||||
while (reservation_size != 0) {
|
||||
current_by_prev_len = (sli_block_metadata_t *)((uint8_t*)current_by_prev_len + reservation_size_real);
|
||||
alignment = sli_memory_get_reservation_align_by_addr((void *)current_by_prev_len);
|
||||
reservation_size = sli_memory_get_reservation_size_by_addr((void *)current_by_prev_len);
|
||||
if (alignment == SL_MEMORY_BLOCK_ALIGN_DEFAULT) {
|
||||
reservation_size_real = reservation_size;
|
||||
} else {
|
||||
reservation_size_real = SLI_ALIGN_ROUND_UP(reservation_size, alignment);
|
||||
}
|
||||
}
|
||||
|
||||
if (current_by_prev_len != current_by_prev_offset) {
|
||||
is_corrupted = 1;
|
||||
break;
|
||||
} else {
|
||||
current = prev_blk_by_offset;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_corrupted) {
|
||||
return (sli_block_metadata_t *)current;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif /* SLI_MEMORY_MANAGER_ENABLE_TEST_UTILITIES */
|
||||
85
Libs/platform/service/mpu/inc/sl_mpu.h
Normal file
85
Libs/platform/service/mpu/inc/sl_mpu.h
Normal file
@@ -0,0 +1,85 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief MPU 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.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/***************************************************************************//**
|
||||
* @addtogroup mpu RAM execution disable
|
||||
* @brief RAM execution disable utilities can be used to disable execution from
|
||||
* RAM and other selected memory regions.
|
||||
* @details
|
||||
* RAM execution disable utilities are useful to protect against code
|
||||
* injection attacks.
|
||||
* These utilities make use of MPU to disable execution from RAM and other
|
||||
* selected memory regions.
|
||||
*
|
||||
* @{
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef SL_MPU_H
|
||||
#define SL_MPU_H
|
||||
|
||||
#include "sl_status.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/***************************************************************************//**
|
||||
* Configures internal SRAM as non-executable and enable MPU.
|
||||
*
|
||||
* @note This function configures the MPU in order to make the entire RAM as
|
||||
* non-executable (with the exception of the functions marked as ramfunc).
|
||||
******************************************************************************/
|
||||
void sl_mpu_disable_execute_from_ram(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Configures an address range as non-executable and enable MPU.
|
||||
*
|
||||
* @note Configures a MPU region in order to make an address range as
|
||||
* non-executable. The memory region must have a size of at least 32 bytes.
|
||||
*
|
||||
* @param address_begin Beginning of memory segment.
|
||||
*
|
||||
* @param address_end End of memory segment.
|
||||
*
|
||||
* @param size Size of memory segment.
|
||||
*
|
||||
* @return 0 if successful. Error code otherwise.
|
||||
******************************************************************************/
|
||||
sl_status_t sl_mpu_disable_execute(uint32_t address_begin,
|
||||
uint32_t address_end,
|
||||
uint32_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SL_MPU_H */
|
||||
|
||||
/** @} (end addtogroup mpu) */
|
||||
493
Libs/platform/service/mpu/src/sl_mpu.c
Normal file
493
Libs/platform/service/mpu/src/sl_mpu.c
Normal file
@@ -0,0 +1,493 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief MPU 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_mpu.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "em_device.h"
|
||||
#include "sl_core.h"
|
||||
|
||||
/*******************************************************************************
|
||||
********************************* DEFINES *********************************
|
||||
******************************************************************************/
|
||||
|
||||
#define MPU_MEMORY_ATTRIBUTE_IX_0 0U
|
||||
#define MPU_MEMORY_ATTRIBUTE_IX_1 1U
|
||||
|
||||
#define MPU_RBAR_BASE_ADDR_NONE 0U
|
||||
#define MPU_RBAR_AP_READ_WRITE 0U
|
||||
#define MPU_RBAR_AP_READ_ONLY 1U
|
||||
#define MPU_RBAR_AP_PRIVILEGED 0U
|
||||
#define MPU_RBAR_AP_NON_PRIVILEGED 1U
|
||||
#define MPU_RBAR_XN_EXECUTION 0U
|
||||
#define MPU_RBAR_XN_NON_EXECUTION 1U
|
||||
|
||||
// Memory region attributes: non-shareable, read-write, non-privileged, non-executable.
|
||||
#define MPU_RBAR_VALUE ARM_MPU_RBAR(MPU_RBAR_BASE_ADDR_NONE, \
|
||||
ARM_MPU_SH_NON, \
|
||||
MPU_RBAR_AP_READ_WRITE, \
|
||||
MPU_RBAR_AP_NON_PRIVILEGED, \
|
||||
MPU_RBAR_XN_NON_EXECUTION)
|
||||
|
||||
// The MPU Region Limit Address Register defines the ending address of an MPU region.
|
||||
// Bit [4:0] of the address value is assigned with 0x1F to provide the limit
|
||||
// address to be checked against.
|
||||
#define MPU_RLAR_LIMIT_ADDRESS_ALIGNMENT 32U
|
||||
|
||||
// ARM memory map SRAM location and size.
|
||||
#if defined(_SILICON_LABS_32B_SERIES_2) \
|
||||
|| (defined(_SILICON_LABS_32B_SERIES_3) && defined(SL_RAM_LINKER))
|
||||
#define MPU_ARM_SRAM_MEM_BASE SRAM_BASE
|
||||
|
||||
// This RAM size is not the real device size. It corresponds to the SRAM max size in the standard
|
||||
// ARM Cortex-M33 memory map. The max size is 0.5GB.
|
||||
#define MPU_ARM_SRAM_MEM_SIZE SRAM_SIZE
|
||||
|
||||
#elif defined(_SILICON_LABS_32B_SERIES_3)
|
||||
// These local constants ensure the MPU regions for the secure/non-secure RAM aliases
|
||||
// and the secure/non-secure RAM non-aliases are properly managed for all
|
||||
// secure/non-secure project configurations.
|
||||
#define MPU_RAMFUNC_SRAM_ALIAS_START SRAM_ALIAS_BASE
|
||||
#define MPU_RAMFUNC_SRAM_ALIAS_END (SRAM_ALIAS_BASE + (SRAM_SIZE - 1U))
|
||||
|
||||
#define MPU_DATA_SRAM_START SRAM_BASE
|
||||
#define MPU_DATA_SRAM_END (SRAM_BASE + (SRAM_SIZE - 1U))
|
||||
|
||||
#if defined(SL_TRUSTZONE_SECURE)
|
||||
#define MPU_NOT_USED_SRAM_ALIAS_START DMEM_INSTR_NS_MEM_BASE
|
||||
#define MPU_NOT_USED_SRAM_ALIAS_END DMEM_INSTR_NS_MEM_END
|
||||
|
||||
#define MPU_NOT_USED_SRAM_START DMEM_NS_MEM_BASE
|
||||
#define MPU_NOT_USED_SRAM_END DMEM_NS_MEM_END
|
||||
#else
|
||||
#define MPU_NOT_USED_SRAM_ALIAS_START DMEM_INSTR_S_MEM_BASE
|
||||
#define MPU_NOT_USED_SRAM_ALIAS_END DMEM_INSTR_S_MEM_END
|
||||
|
||||
#define MPU_NOT_USED_SRAM_START DMEM_S_MEM_BASE
|
||||
#define MPU_NOT_USED_SRAM_END DMEM_S_MEM_END
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__ICCARM__)
|
||||
// iccarm
|
||||
#pragma section = "text_ram"
|
||||
#define RAMFUNC_SECTION_BEGIN ((uint32_t)(uint32_t *)__section_begin("text_ram"))
|
||||
#define RAMFUNC_SECTION_END ((uint32_t)(uint32_t *)__section_end("text_ram"))
|
||||
#define RAMFUNC_SECTION_SIZE __section_size("text_ram")
|
||||
|
||||
#elif defined(__GNUC__)
|
||||
// armgcc
|
||||
extern uint32_t __vma_ramfuncs_start__;
|
||||
extern uint32_t __vma_ramfuncs_end__;
|
||||
#define RAMFUNC_SECTION_BEGIN (uint32_t) &__vma_ramfuncs_start__
|
||||
#define RAMFUNC_SECTION_END (uint32_t) &__vma_ramfuncs_end__
|
||||
#define RAMFUNC_SECTION_SIZE (RAMFUNC_SECTION_END - RAMFUNC_SECTION_BEGIN)
|
||||
|
||||
#elif defined(__CC_ARM)
|
||||
// armcc
|
||||
// The section name in the armcc scatter file must be "ram_code".
|
||||
extern uint32_t ram_code$$Base;
|
||||
extern uint32_t ram_code$$Limit;
|
||||
#define RAMFUNC_SECTION_BEGIN (uint32_t) &ram_code$$Base
|
||||
#define RAMFUNC_SECTION_END (uint32_t) &ram_code$$Limit
|
||||
#define RAMFUNC_SECTION_SIZE (RAMFUNC_SECTION_END - RAMFUNC_SECTION_BEGIN)
|
||||
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
*************************** LOCAL VARIABLES ********************************
|
||||
******************************************************************************/
|
||||
|
||||
static uint32_t region_nbr = 0;
|
||||
|
||||
/*******************************************************************************
|
||||
************************** GLOBAL FUNCTIONS *******************************
|
||||
******************************************************************************/
|
||||
|
||||
/**************************************************************************//**
|
||||
* Configures internal SRAM as non-executable and enable MPU.
|
||||
*
|
||||
* @note (1) On series 2 devices, the MPU regions configuration for the RAM layout
|
||||
* is for GCC and IAR:
|
||||
*
|
||||
* MPU Region Region Attributes Adresses Range
|
||||
* ------------------------------------------------------------------------
|
||||
* 0x2000_0000 0x2007_FFFF (DATA, RAMFUNC) 0 non shareable, executable RAMFunc start to RAMFunc end
|
||||
* 1 non shareable, non executable RAMFunc end to range end
|
||||
* or
|
||||
* 0x2000_0000 0x2007_FFFF (DATA) 0 shareable, non executable Entire range
|
||||
*
|
||||
* @note (2) On series 3 SIXG301 devices, there are the following RAM-related
|
||||
* address ranges.
|
||||
* - 0x0080_0000 0x0087_FFFF (Alias to DMEM_NS) - Non-secure
|
||||
* - 0x1080_0000 0x1087_FFFF (Alias to DMEM (execute only)) -Secure
|
||||
* - 0x2000_0000 0x2007_FFFF (DMEM_NS) - Non-secure
|
||||
* - 0x3000_0000 0x3007_FFFF (DMEM) - Secure
|
||||
*
|
||||
* The MPU regions are configured differently depending on the RAM layout
|
||||
* described in GCC and IAR linker scripts. A common characteristic
|
||||
* to all the MPU regions for GCC and IAR is:
|
||||
* - All MPU regions for RAM are non-cacheable.
|
||||
*
|
||||
* The table below presents the MPU regions for series 3 SIXG301 devices.
|
||||
* The table assumes there are RAMFunc in RAM. If there are no RAMFunc
|
||||
* functions, then the associated region will be a single region covering
|
||||
* the full addresses range.
|
||||
*
|
||||
* GCC
|
||||
* ---
|
||||
* MPU Region* Region Attributes Adresses Range
|
||||
* ------------------------------------------------------------------------
|
||||
* 0x0080_0000 0x0087_FFFF (RAMFUNC)* 0 shareable, executable RAMFunc start to RAMFunc end
|
||||
* 1 non shareable, non executable RAMFunc end to range end
|
||||
* or
|
||||
* 0x0080_0000 0x0087_FFFF (NOT USED)* x non shareable, non executable Entire range (if no RAMFunc)
|
||||
*
|
||||
* 0x1080_0000 0x1087_FFFF (NOT USED)* 2 non shareable, non executable Entire range
|
||||
* 0x2000_0000 0x2007_FFFF (DATA)* 3 shareable, non executable Entire range
|
||||
* 0x3000_0000 0x3007_FFFF (NOT USED)* 4 non shareable, non executable Entire range
|
||||
*
|
||||
* IAR
|
||||
* ---
|
||||
* MPU Region* Region Attributes Adresses Range
|
||||
* ------------------------------------------------------------------------
|
||||
* 0x0080_0000 0x0087_FFFF (NOT USED)* 0 non shareable, non executable Entire range
|
||||
* 0x1080_0000 0x1087_FFFF (NOT USED)* 1 non shareable, non executable Entire range
|
||||
* 0x2000_0000 0x2007_FFFF (DATA, RAMFUNC)* 2 shareable, non executable Range start to RAMFunc start
|
||||
* 3 shareable, executable RAMFunc start to RAMFunc end
|
||||
* 4 shareable, non executable RAMFunc end to range end
|
||||
* or
|
||||
* 0x2000_0000 0x2007_FFFF (NOT USED)* x non shareable, non executable Entire range (if no RAMFunc)
|
||||
*
|
||||
* 0x3000_0000 0x3007_FFFF (NOT USED)* 5 non shareable, non executable Entire range
|
||||
|
||||
* *If the ARM Cortex-M33 works in non-secure, all non-secure alias/
|
||||
* non-alias will be used by default for RAMfunc and data in RAM.
|
||||
* Same logic if the Cortex-M33 is in secure, all secure alias/non-alias
|
||||
* will be used by default. The MPU regions creation will adapt to
|
||||
* the default secure or non-secure addresses. And thus the order
|
||||
* in which the MPU regions are created can vary.
|
||||
*****************************************************************************/
|
||||
void sl_mpu_disable_execute_from_ram(void)
|
||||
{
|
||||
uint32_t mpu_region_begin = 0u;
|
||||
uint32_t mpu_region_end = 0u;
|
||||
uint32_t rbar;
|
||||
|
||||
ARM_MPU_Disable();
|
||||
|
||||
// See Note #1.
|
||||
#if defined(_SILICON_LABS_32B_SERIES_2) \
|
||||
|| (defined(_SILICON_LABS_32B_SERIES_3) && defined(SL_RAM_LINKER))
|
||||
// Memory attributes:
|
||||
// Outer memory with ARM_MPU_ATTR_MEMORY_(): non-transient data, Write-Through, cache allocation on read miss, no cache allocation on write miss.
|
||||
// ARM_MPU_ATTR(): outer attributes filled, no inner memory
|
||||
ARM_MPU_SetMemAttr(MPU_MEMORY_ATTRIBUTE_IX_0,
|
||||
ARM_MPU_ATTR(ARM_MPU_ATTR_MEMORY_(1, 0, 1, 0), 0));
|
||||
|
||||
// Region end address LSB are always considered 0x1F.
|
||||
mpu_region_begin = MPU_ARM_SRAM_MEM_BASE;
|
||||
mpu_region_end = (RAMFUNC_SECTION_SIZE > 0) ? (RAMFUNC_SECTION_BEGIN & MPU_RBAR_BASE_Msk) - MPU_RLAR_LIMIT_ADDRESS_ALIGNMENT
|
||||
: (MPU_ARM_SRAM_MEM_BASE + MPU_ARM_SRAM_MEM_SIZE);
|
||||
|
||||
// Define initial MPU region: either 1 unique region = entire RAM. Or 1 region = from RAM START to RAMFUNC START.
|
||||
if (mpu_region_begin <= mpu_region_end) {
|
||||
// A bug exists in some versions of ARM_MPU_RBAR(). Set base addr manually.
|
||||
rbar = MPU_RBAR_VALUE | (mpu_region_begin & MPU_RBAR_BASE_Msk);
|
||||
ARM_MPU_SetRegion(region_nbr, rbar, ARM_MPU_RLAR(mpu_region_end, MPU_MEMORY_ATTRIBUTE_IX_0));
|
||||
region_nbr++;
|
||||
}
|
||||
|
||||
// Only if functions placed in RAM, define another region from RAMFUNC END to RAM END.
|
||||
if (RAMFUNC_SECTION_SIZE > 0u) {
|
||||
// Region end address LSB are always considered 0x1F.
|
||||
mpu_region_begin = (RAMFUNC_SECTION_END + 31u) & MPU_RLAR_LIMIT_Msk;
|
||||
mpu_region_end = MPU_ARM_SRAM_MEM_BASE + MPU_ARM_SRAM_MEM_SIZE - MPU_RLAR_LIMIT_ADDRESS_ALIGNMENT;
|
||||
|
||||
// A bug exists in some versions of ARM_MPU_RBAR(). Set base addr manually.
|
||||
rbar = MPU_RBAR_VALUE | (mpu_region_begin & MPU_RBAR_BASE_Msk);
|
||||
ARM_MPU_SetRegion(region_nbr, rbar, ARM_MPU_RLAR(mpu_region_end, 0u));
|
||||
region_nbr++;
|
||||
}
|
||||
|
||||
// See Note #2.
|
||||
#elif (defined(_SILICON_LABS_32B_SERIES_3) && !defined(SL_RAM_LINKER))
|
||||
// 1. Set the memory attributes for the entire RAM (alias and non-alias ranges).
|
||||
// Outer & inner memories: non-cacheable.
|
||||
ARM_MPU_SetMemAttr(MPU_MEMORY_ATTRIBUTE_IX_0,
|
||||
ARM_MPU_ATTR(ARM_MPU_ATTR_NON_CACHEABLE, ARM_MPU_ATTR_NON_CACHEABLE));
|
||||
|
||||
// 2. Create different MPU regions accounting for all RAM addresses ranges (secure/non-secure alias/non-alias)
|
||||
// Secure or non secure alias (not used): 1 region (non shareable, non cacheable, non executable)
|
||||
mpu_region_begin = MPU_NOT_USED_SRAM_ALIAS_START;
|
||||
rbar = ARM_MPU_RBAR(MPU_RBAR_BASE_ADDR_NONE,
|
||||
ARM_MPU_SH_NON,
|
||||
MPU_RBAR_AP_READ_ONLY,
|
||||
MPU_RBAR_AP_NON_PRIVILEGED,
|
||||
MPU_RBAR_XN_NON_EXECUTION)
|
||||
| (mpu_region_begin & MPU_RBAR_BASE_Msk);
|
||||
mpu_region_end = (MPU_NOT_USED_SRAM_ALIAS_END & MPU_RLAR_LIMIT_Msk);
|
||||
ARM_MPU_SetRegion(region_nbr, rbar, ARM_MPU_RLAR(mpu_region_end, MPU_MEMORY_ATTRIBUTE_IX_0));
|
||||
region_nbr++;
|
||||
|
||||
// Non secure or secure alias (used for code if functions placed in RAM):
|
||||
#if defined(__GNUC__)
|
||||
if (RAMFUNC_SECTION_SIZE > 0u) {
|
||||
// Functions placed in RAM: 1 region (shareable, non cacheable, executable)
|
||||
mpu_region_begin = RAMFUNC_SECTION_BEGIN;
|
||||
rbar = ARM_MPU_RBAR(MPU_RBAR_BASE_ADDR_NONE,
|
||||
ARM_MPU_SH_OUTER,
|
||||
MPU_RBAR_AP_READ_ONLY,
|
||||
MPU_RBAR_AP_NON_PRIVILEGED,
|
||||
MPU_RBAR_XN_EXECUTION)
|
||||
| (mpu_region_begin & MPU_RBAR_BASE_Msk);
|
||||
mpu_region_end = (RAMFUNC_SECTION_END & MPU_RLAR_LIMIT_Msk);
|
||||
ARM_MPU_SetRegion(region_nbr, rbar, ARM_MPU_RLAR(mpu_region_end, MPU_MEMORY_ATTRIBUTE_IX_0));
|
||||
region_nbr++;
|
||||
|
||||
// Rest of the non secure or secure alias: non shareable, non cacheable, non executable
|
||||
mpu_region_begin = (RAMFUNC_SECTION_END + 31u) & MPU_RLAR_LIMIT_Msk; // +31u allows to round up to the next 32 bytes alignment.
|
||||
rbar = ARM_MPU_RBAR(MPU_RBAR_BASE_ADDR_NONE,
|
||||
ARM_MPU_SH_NON,
|
||||
MPU_RBAR_AP_READ_ONLY,
|
||||
MPU_RBAR_AP_NON_PRIVILEGED,
|
||||
MPU_RBAR_XN_NON_EXECUTION)
|
||||
| (mpu_region_begin & MPU_RBAR_BASE_Msk);
|
||||
mpu_region_end = (MPU_RAMFUNC_SRAM_ALIAS_END & MPU_RLAR_LIMIT_Msk);
|
||||
ARM_MPU_SetRegion(region_nbr, rbar, ARM_MPU_RLAR(mpu_region_end, MPU_MEMORY_ATTRIBUTE_IX_0));
|
||||
region_nbr++;
|
||||
} else {
|
||||
#endif
|
||||
// No functions placed in RAM: 1 region (non shareable, non cacheable, non executable)
|
||||
mpu_region_begin = MPU_RAMFUNC_SRAM_ALIAS_START;
|
||||
rbar = ARM_MPU_RBAR(MPU_RBAR_BASE_ADDR_NONE,
|
||||
ARM_MPU_SH_NON,
|
||||
MPU_RBAR_AP_READ_ONLY,
|
||||
MPU_RBAR_AP_NON_PRIVILEGED,
|
||||
MPU_RBAR_XN_NON_EXECUTION)
|
||||
| (mpu_region_begin & MPU_RBAR_BASE_Msk);
|
||||
mpu_region_end = (MPU_RAMFUNC_SRAM_ALIAS_END & MPU_RLAR_LIMIT_Msk);
|
||||
ARM_MPU_SetRegion(region_nbr, rbar, ARM_MPU_RLAR(mpu_region_end, MPU_MEMORY_ATTRIBUTE_IX_0));
|
||||
region_nbr++;
|
||||
#if defined(__GNUC__)
|
||||
}
|
||||
#endif
|
||||
|
||||
// Secure or non secure non alias (used for data): 1 region (shareable, non cacheable, non executable)
|
||||
#if defined(__ICCARM__)
|
||||
if (RAMFUNC_SECTION_SIZE > 0u) {
|
||||
// Beginning of non secure alias: shareable, non cacheable, non executable
|
||||
mpu_region_begin = MPU_DATA_SRAM_START;
|
||||
rbar = ARM_MPU_RBAR(MPU_RBAR_BASE_ADDR_NONE,
|
||||
ARM_MPU_SH_OUTER,
|
||||
MPU_RBAR_AP_READ_WRITE,
|
||||
MPU_RBAR_AP_NON_PRIVILEGED,
|
||||
MPU_RBAR_XN_NON_EXECUTION)
|
||||
| (mpu_region_begin & MPU_RBAR_BASE_Msk);
|
||||
mpu_region_end = ((RAMFUNC_SECTION_BEGIN - 1u) & MPU_RLAR_LIMIT_Msk);
|
||||
ARM_MPU_SetRegion(region_nbr, rbar, ARM_MPU_RLAR(mpu_region_end, MPU_MEMORY_ATTRIBUTE_IX_0));
|
||||
region_nbr++;
|
||||
|
||||
// Functions placed in RAM: 1 region (shareable, non cacheable, executable)
|
||||
mpu_region_begin = RAMFUNC_SECTION_BEGIN;
|
||||
rbar = ARM_MPU_RBAR(MPU_RBAR_BASE_ADDR_NONE,
|
||||
ARM_MPU_SH_OUTER,
|
||||
MPU_RBAR_AP_READ_ONLY,
|
||||
MPU_RBAR_AP_NON_PRIVILEGED,
|
||||
MPU_RBAR_XN_EXECUTION)
|
||||
| (mpu_region_begin & MPU_RBAR_BASE_Msk);
|
||||
mpu_region_end = (RAMFUNC_SECTION_END & MPU_RLAR_LIMIT_Msk);
|
||||
ARM_MPU_SetRegion(region_nbr, rbar, ARM_MPU_RLAR(mpu_region_end, MPU_MEMORY_ATTRIBUTE_IX_0));
|
||||
region_nbr++;
|
||||
|
||||
// Rest of non secure alias: shareable, non cacheable, non executable
|
||||
mpu_region_begin = (RAMFUNC_SECTION_END + 31u) & MPU_RLAR_LIMIT_Msk; // +31u allows to round up to the next 32 bytes alignment.
|
||||
rbar = ARM_MPU_RBAR(MPU_RBAR_BASE_ADDR_NONE,
|
||||
ARM_MPU_SH_OUTER,
|
||||
MPU_RBAR_AP_READ_WRITE,
|
||||
MPU_RBAR_AP_NON_PRIVILEGED,
|
||||
MPU_RBAR_XN_NON_EXECUTION)
|
||||
| (mpu_region_begin & MPU_RBAR_BASE_Msk);
|
||||
mpu_region_end = (MPU_DATA_SRAM_END & MPU_RLAR_LIMIT_Msk);
|
||||
ARM_MPU_SetRegion(region_nbr, rbar, ARM_MPU_RLAR(mpu_region_end, MPU_MEMORY_ATTRIBUTE_IX_0));
|
||||
region_nbr++;
|
||||
} else {
|
||||
#endif
|
||||
mpu_region_begin = MPU_DATA_SRAM_START;
|
||||
rbar = ARM_MPU_RBAR(MPU_RBAR_BASE_ADDR_NONE,
|
||||
ARM_MPU_SH_OUTER,
|
||||
MPU_RBAR_AP_READ_WRITE,
|
||||
MPU_RBAR_AP_NON_PRIVILEGED,
|
||||
MPU_RBAR_XN_NON_EXECUTION)
|
||||
| (mpu_region_begin & MPU_RBAR_BASE_Msk);
|
||||
mpu_region_end = (MPU_DATA_SRAM_END & MPU_RLAR_LIMIT_Msk);
|
||||
ARM_MPU_SetRegion(region_nbr, rbar, ARM_MPU_RLAR(mpu_region_end, MPU_MEMORY_ATTRIBUTE_IX_0));
|
||||
region_nbr++;
|
||||
#if defined(__ICCARM__)
|
||||
}
|
||||
#endif
|
||||
|
||||
// Non secure or secure non alias (not used): 1 region (non shareable, non cacheable, non executable)
|
||||
mpu_region_begin = MPU_NOT_USED_SRAM_START;
|
||||
rbar = ARM_MPU_RBAR(MPU_RBAR_BASE_ADDR_NONE,
|
||||
ARM_MPU_SH_NON,
|
||||
MPU_RBAR_AP_READ_ONLY,
|
||||
MPU_RBAR_AP_NON_PRIVILEGED,
|
||||
MPU_RBAR_XN_NON_EXECUTION)
|
||||
| (mpu_region_begin & MPU_RBAR_BASE_Msk);
|
||||
mpu_region_end = (MPU_NOT_USED_SRAM_END & MPU_RLAR_LIMIT_Msk);
|
||||
ARM_MPU_SetRegion(region_nbr, rbar, ARM_MPU_RLAR(mpu_region_end, MPU_MEMORY_ATTRIBUTE_IX_0));
|
||||
region_nbr++;
|
||||
#else
|
||||
(void)rbar;
|
||||
(void)mpu_region_begin;
|
||||
(void)mpu_region_end;
|
||||
#endif
|
||||
|
||||
// Enable MPU with default background region.
|
||||
ARM_MPU_Enable(MPU_CTRL_PRIVDEFENA_Msk);
|
||||
|
||||
__DSB();
|
||||
__ISB();
|
||||
}
|
||||
|
||||
/**************************************************************************//**
|
||||
* Enables simplified MPU driver. Configures memory address as non-executable.
|
||||
*****************************************************************************/
|
||||
sl_status_t sl_mpu_disable_execute(uint32_t address_begin,
|
||||
uint32_t address_end,
|
||||
uint32_t size)
|
||||
{
|
||||
uint32_t mpu_region_begin = 0u;
|
||||
uint32_t mpu_region_end = 0u;
|
||||
sl_status_t status = SL_STATUS_OK;
|
||||
|
||||
// Ensure there is still an available MPU region to configure.
|
||||
if (region_nbr > MPU_RNR_REGION_Msk) {
|
||||
status = SL_STATUS_NO_MORE_RESOURCE;
|
||||
}
|
||||
|
||||
ARM_MPU_Disable();
|
||||
|
||||
uint32_t rbar;
|
||||
uint8_t is_overlapping = 0u;
|
||||
uint32_t prev_base_address = 0u;
|
||||
uint32_t prev_limit_address = 0u;
|
||||
|
||||
// Size of memory region must be 32 bytes or more.
|
||||
if (size >= 32u) {
|
||||
// Round inside the memory region, if address is not align on 32 bytes.
|
||||
mpu_region_begin = ((address_begin % 32u) == 0u) ? address_begin
|
||||
: (address_begin + (32u - (address_begin % 32u)));
|
||||
|
||||
// Round inside the memory region, if address is not align on 32 bytes.
|
||||
mpu_region_end = ((address_end % 32u) == 0u) ? address_end
|
||||
: (address_end - (address_end % 32u));
|
||||
|
||||
// The scanning to check the overlapping region
|
||||
for (uint8_t index_region = 0; index_region < region_nbr; index_region++) {
|
||||
// Set to the previous region number
|
||||
MPU->RNR = index_region;
|
||||
|
||||
// Read the base address that was configured by the region number register before
|
||||
prev_base_address = (MPU->RBAR & MPU_RBAR_BASE_Msk);
|
||||
// Read the limit address that was configured by the region number register before
|
||||
prev_limit_address = (MPU->RLAR & MPU_RLAR_LIMIT_Msk);
|
||||
|
||||
// Check the overlapping region
|
||||
if ((mpu_region_begin == prev_base_address) && (mpu_region_end == prev_limit_address)) {
|
||||
// The new region is the same as the previous region
|
||||
is_overlapping = 1;
|
||||
status = SL_STATUS_OK;
|
||||
} else if (!((mpu_region_begin > prev_limit_address) || (mpu_region_end < prev_base_address))) {
|
||||
// The new region is invalid
|
||||
is_overlapping = 1;
|
||||
status = SL_STATUS_INVALID_RANGE;
|
||||
}
|
||||
|
||||
if (is_overlapping == 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
MPU->RNR &= ~MPU_RNR_REGION_Msk;
|
||||
}
|
||||
|
||||
// Set specified memory region if no overlap has been detected.
|
||||
if (!is_overlapping) {
|
||||
// Device memory type non Gathering, non Re-ordering, Early Write Acknowledgment
|
||||
ARM_MPU_SetMemAttr(MPU_MEMORY_ATTRIBUTE_IX_1, ARM_MPU_ATTR_DEVICE_nGnRE);
|
||||
|
||||
// A bug exists in some versions of ARM_MPU_RBAR(). Set base addr manually.
|
||||
// Memory region attributes: non-shareable, read-write, non-privileged, non-executable
|
||||
rbar = ARM_MPU_RBAR(MPU_RBAR_BASE_ADDR_NONE,
|
||||
ARM_MPU_SH_NON,
|
||||
MPU_RBAR_AP_READ_WRITE,
|
||||
MPU_RBAR_AP_NON_PRIVILEGED,
|
||||
MPU_RBAR_XN_NON_EXECUTION)
|
||||
| (mpu_region_begin & MPU_RBAR_BASE_Msk);
|
||||
|
||||
CORE_DECLARE_IRQ_STATE;
|
||||
CORE_ENTER_ATOMIC();
|
||||
ARM_MPU_SetRegion(region_nbr, rbar, ARM_MPU_RLAR(mpu_region_end, MPU_MEMORY_ATTRIBUTE_IX_1));
|
||||
CORE_EXIT_ATOMIC();
|
||||
region_nbr++;
|
||||
}
|
||||
}
|
||||
|
||||
// Enable MPU with default background region
|
||||
ARM_MPU_Enable(MPU_CTRL_PRIVDEFENA_Msk);
|
||||
|
||||
__DSB();
|
||||
__ISB();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
#if __CORTEX_M != (0u)
|
||||
/**************************************************************************//**
|
||||
* MemManage default exception handler. Reset target.
|
||||
*****************************************************************************/
|
||||
__WEAK void mpu_fault_handler(void)
|
||||
{
|
||||
// Force fail assert to trigger reset
|
||||
__NVIC_SystemReset();
|
||||
}
|
||||
|
||||
/**************************************************************************//**
|
||||
* MemManage exception handler.
|
||||
*****************************************************************************/
|
||||
void MemManage_Handler(void)
|
||||
{
|
||||
mpu_fault_handler();
|
||||
}
|
||||
#endif
|
||||
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
|
||||
1184
Libs/platform/service/sleeptimer/inc/sl_sleeptimer.h
Normal file
1184
Libs/platform/service/sleeptimer/inc/sl_sleeptimer.h
Normal file
File diff suppressed because it is too large
Load Diff
143
Libs/platform/service/sleeptimer/inc/sli_sleeptimer.h
Normal file
143
Libs/platform/service/sleeptimer/inc/sli_sleeptimer.h
Normal file
@@ -0,0 +1,143 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief SLEEPTIMER SDK internal APIs.
|
||||
*******************************************************************************
|
||||
* # 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_SLEEPTIMER_H
|
||||
#define SLI_SLEEPTIMER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include "em_device.h"
|
||||
#include "sl_sleeptimer_config.h"
|
||||
#include "sl_code_classification.h"
|
||||
|
||||
#define SLEEPTIMER_EVENT_OF (0x01)
|
||||
#define SLEEPTIMER_EVENT_COMP (0x02)
|
||||
|
||||
#define SLI_SLEEPTIMER_POWER_MANAGER_EARLY_WAKEUP_TIMER_FLAG 0x02
|
||||
#define SLI_SLEEPTIMER_POWER_MANAGER_HF_ACCURACY_CLK_FLAG 0x04
|
||||
|
||||
#if SL_SLEEPTIMER_PERIPHERAL == SL_SLEEPTIMER_PERIPHERAL_DEFAULT
|
||||
#if defined(RTCC_PRESENT) && RTCC_COUNT >= 1
|
||||
#undef SL_SLEEPTIMER_PERIPHERAL
|
||||
#define SL_SLEEPTIMER_PERIPHERAL SL_SLEEPTIMER_PERIPHERAL_RTCC
|
||||
#elif defined(RTC_PRESENT) && RTC_COUNT >= 1
|
||||
#undef SL_SLEEPTIMER_PERIPHERAL
|
||||
#define SL_SLEEPTIMER_PERIPHERAL SL_SLEEPTIMER_PERIPHERAL_RTC
|
||||
#elif defined(SYSRTC_PRESENT) && SYSRTC_COUNT >= 1
|
||||
#undef SL_SLEEPTIMER_PERIPHERAL
|
||||
#define SL_SLEEPTIMER_PERIPHERAL SL_SLEEPTIMER_PERIPHERAL_SYSRTC
|
||||
#elif defined(BURTC_PRESENT) && BURTC_COUNT >= 1
|
||||
#undef SL_SLEEPTIMER_PERIPHERAL
|
||||
#define SL_SLEEPTIMER_PERIPHERAL SL_SLEEPTIMER_PERIPHERAL_BURTC
|
||||
#elif defined(WTIMER_PRESENT) && WTIMER_COUNT >= 1
|
||||
#undef SL_SLEEPTIMER_PERIPHERAL
|
||||
#define SL_SLEEPTIMER_PERIPHERAL SL_SLEEPTIMER_PERIPHERAL_WTIMER
|
||||
#elif defined(TIMER_PRESENT) && TIMER_COUNT >= 1
|
||||
#undef SL_SLEEPTIMER_PERIPHERAL
|
||||
#define SL_SLEEPTIMER_PERIPHERAL SL_SLEEPTIMER_PERIPHERAL_TIMER
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
* Hardware Abstraction Layer to perform initialization related to Power Manager.
|
||||
******************************************************************************/
|
||||
__WEAK void sli_sleeptimer_hal_power_manager_integration_init(void);
|
||||
|
||||
/*******************************************************************************
|
||||
* Hardware Abstraction Layer to perform initialization related to HFXO Manager.
|
||||
******************************************************************************/
|
||||
__WEAK void sli_sleeptimer_hal_hfxo_manager_integration_init(void);
|
||||
|
||||
/*******************************************************************************
|
||||
* Hardware Abstraction Layer to get interrupt status.
|
||||
*
|
||||
* @param local_flag Internal interrupt flag.
|
||||
*
|
||||
* @return Boolean indicating if specified interrupt is set.
|
||||
******************************************************************************/
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_SLEEPTIMER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
bool sli_sleeptimer_hal_is_int_status_set(uint8_t local_flag);
|
||||
|
||||
/**************************************************************************//**
|
||||
* Determines if next timer to expire has the option flag
|
||||
* "SLI_SLEEPTIMER_POWER_MANAGER_EARLY_WAKEUP_TIMER_FLAG".
|
||||
*
|
||||
* @return true if power manager will expire at next compare match,
|
||||
* false otherwise.
|
||||
*****************************************************************************/
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_SLEEPTIMER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
bool sli_sleeptimer_is_power_manager_timer_next_to_expire(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Set lowest energy mode based on a project's configurations and clock source
|
||||
*
|
||||
* @note If power_manager_no_deepsleep component is included in a project, the
|
||||
* lowest possible energy mode is EM1, else lowest energy mode is
|
||||
* determined by clock source.
|
||||
******************************************************************************/
|
||||
#if defined(SL_CATALOG_POWER_MANAGER_PRESENT)
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_SLEEPTIMER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
void sli_sleeptimer_set_pm_em_requirement(void);
|
||||
#endif
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Update sleep_on_isr_exit flag.
|
||||
*
|
||||
* @param flag Boolean value update_sleep_on_isr_exit will be set to.
|
||||
******************************************************************************/
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_SLEEPTIMER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
void sli_sleeptimer_update_sleep_on_isr_exit(bool flag);
|
||||
|
||||
/*******************************************************************************
|
||||
* Gets the associated peripheral capture channel current value.
|
||||
*
|
||||
* @return Capture value
|
||||
* 0 if capture channel is not valid
|
||||
******************************************************************************/
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_SLEEPTIMER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
uint32_t sli_sleeptimer_get_capture(void);
|
||||
|
||||
/*******************************************************************************
|
||||
* Resets the PRS signal triggered by the associated peripheral.
|
||||
******************************************************************************/
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_SLEEPTIMER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
void sli_sleeptimer_reset_prs_signal(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SLI_SLEEPTIMER_H */
|
||||
1967
Libs/platform/service/sleeptimer/src/sl_sleeptimer.c
Normal file
1967
Libs/platform/service/sleeptimer/src/sl_sleeptimer.c
Normal file
File diff suppressed because it is too large
Load Diff
381
Libs/platform/service/sleeptimer/src/sl_sleeptimer_hal_burtc.c
Normal file
381
Libs/platform/service/sleeptimer/src/sl_sleeptimer_hal_burtc.c
Normal file
@@ -0,0 +1,381 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief SLEEPTIMER Hardware abstraction implementation for BURTC.
|
||||
*******************************************************************************
|
||||
* # License
|
||||
* <b>Copyright 2020 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) || defined(_SILICON_LABS_32B_SERIES_3)
|
||||
|
||||
// Define module name for Power Manager debug feature
|
||||
#define CURRENT_MODULE_NAME "SLEEPTIMER_BURTC"
|
||||
|
||||
#include "sl_sleeptimer.h"
|
||||
#include "sli_sleeptimer_hal.h"
|
||||
|
||||
#include "sl_core.h"
|
||||
|
||||
#if defined(_SILICON_LABS_32B_SERIES_2)
|
||||
#include "em_burtc.h"
|
||||
|
||||
#define sleeptimer_hal_burtc_get_counter() BURTC_CounterGet()
|
||||
#define sleeptimer_hal_burtc_get_compare() BURTC_CompareGet(0U)
|
||||
#define sleeptimer_hal_burtc_set_compare(compare) BURTC_CompareSet(0, compare)
|
||||
#define sleeptimer_hal_burtc_get_interrupts() BURTC_IntGet()
|
||||
#define sleeptimer_hal_burtc_set_interrupts(flags) BURTC_IntSet(flags)
|
||||
#define sleeptimer_hal_burtc_enable_interrupts(interrupts) BURTC_IntEnable(interrupts)
|
||||
#define sleeptimer_hal_burtc_disable_interrupts(interrupts) BURTC_IntDisable(interrupts)
|
||||
#define sleeptimer_hal_burtc_clear_interrupts(flags) BURTC_IntClear(flags)
|
||||
|
||||
#elif defined(_SILICON_LABS_32B_SERIES_3)
|
||||
#include "sl_hal_burtc.h"
|
||||
|
||||
#define sleeptimer_hal_burtc_get_counter() sl_hal_burtc_get_counter()
|
||||
#define sleeptimer_hal_burtc_get_compare() sl_hal_burtc_get_compare()
|
||||
#define sleeptimer_hal_burtc_set_compare(compare) sl_hal_burtc_set_compare(compare)
|
||||
#define sleeptimer_hal_burtc_get_interrupts() sl_hal_burtc_get_pending_interrupts()
|
||||
#define sleeptimer_hal_burtc_set_interrupts(flags) sl_hal_burtc_set_interrupts(flags)
|
||||
#define sleeptimer_hal_burtc_enable_interrupts(interrupts) sl_hal_burtc_enable_interrupts(interrupts)
|
||||
#define sleeptimer_hal_burtc_disable_interrupts(interrupts) sl_hal_burtc_disable_interrupts(interrupts)
|
||||
#define sleeptimer_hal_burtc_clear_interrupts(flags) sl_hal_burtc_clear_interrupts(flags)
|
||||
|
||||
#endif
|
||||
|
||||
#include "sl_clock_manager.h"
|
||||
#include "sl_device_peripheral.h"
|
||||
#include "sl_interrupt_manager.h"
|
||||
|
||||
#if defined(SL_CATALOG_POWER_MANAGER_PRESENT)
|
||||
#include "sl_power_manager.h"
|
||||
#endif
|
||||
|
||||
#if SL_SLEEPTIMER_PERIPHERAL == SL_SLEEPTIMER_PERIPHERAL_BURTC
|
||||
|
||||
#if defined(_SILICON_LABS_32B_SERIES_0)
|
||||
#error BURTC implementation of the sleeptimer not available on Series 0 chips
|
||||
#endif
|
||||
|
||||
// Minimum difference between current count value and what the comparator of the timer can be set to.
|
||||
// 1 tick is added to the minimum diff for the algorithm of compensation for the IRQ handler that
|
||||
// triggers when CNT == compare_value + 1. For more details refer to sleeptimer_hal_set_compare() function's header.
|
||||
#if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_8)
|
||||
#define SLEEPTIMER_COMPARE_MIN_DIFF (5 + 1)
|
||||
#else
|
||||
#define SLEEPTIMER_COMPARE_MIN_DIFF (4 + 1)
|
||||
#endif
|
||||
|
||||
#define SLEEPTIMER_TMR_WIDTH (_BURTC_CNT_MASK)
|
||||
|
||||
static uint32_t get_time_diff(uint32_t a, uint32_t b);
|
||||
|
||||
/******************************************************************************
|
||||
* Convert HAL interrupt flag BURTC-interrupt-enable bitmask
|
||||
*****************************************************************************/
|
||||
static uint32_t irqien_hal2burtc(uint8_t hal_flag)
|
||||
{
|
||||
uint32_t burtc_if = 0u;
|
||||
|
||||
if (hal_flag & SLEEPTIMER_EVENT_OF) {
|
||||
burtc_if |= BURTC_IEN_OF;
|
||||
}
|
||||
|
||||
if (hal_flag & SLEEPTIMER_EVENT_COMP) {
|
||||
burtc_if |= BURTC_IEN_COMP;
|
||||
}
|
||||
|
||||
return burtc_if;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Convert BURTC interrupt flags to HAL events
|
||||
*****************************************************************************/
|
||||
static uint8_t irqflags_burtc2hal(uint32_t burtc_flag)
|
||||
{
|
||||
uint8_t hal_if = 0u;
|
||||
|
||||
if (burtc_flag & BURTC_IF_OF) {
|
||||
hal_if |= SLEEPTIMER_EVENT_OF;
|
||||
}
|
||||
|
||||
if (burtc_flag & BURTC_IF_COMP) {
|
||||
hal_if |= SLEEPTIMER_EVENT_COMP;
|
||||
}
|
||||
|
||||
return hal_if;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Initializes BURTC sleep timer.
|
||||
*****************************************************************************/
|
||||
void sleeptimer_hal_init_timer()
|
||||
{
|
||||
sl_clock_manager_enable_bus_clock(SL_BUS_CLOCK_BURTC);
|
||||
|
||||
#if defined(_SILICON_LABS_32B_SERIES_2)
|
||||
BURTC_Init_TypeDef burtc_init = BURTC_INIT_DEFAULT;
|
||||
|
||||
burtc_init.start = false;
|
||||
burtc_init.clkDiv = SL_SLEEPTIMER_FREQ_DIVIDER;
|
||||
#if (SL_SLEEPTIMER_DEBUGRUN == 1)
|
||||
burtc_init.debugRun = true;
|
||||
#endif
|
||||
|
||||
BURTC_Init(&burtc_init);
|
||||
BURTC_IntDisable(_BURTC_IEN_MASK);
|
||||
BURTC_IntClear(_BURTC_IF_MASK);
|
||||
BURTC_CounterReset();
|
||||
|
||||
BURTC_Start();
|
||||
BURTC_SyncWait();
|
||||
#elif defined(_SILICON_LABS_32B_SERIES_3)
|
||||
sl_hal_burtc_init_config_t burtc_init = SL_HAL_BURTC_INIT_DEFAULT;
|
||||
|
||||
burtc_init.clock_divider = SL_SLEEPTIMER_FREQ_DIVIDER;
|
||||
#if (SL_SLEEPTIMER_DEBUGRUN == 1)
|
||||
burtc_init.debug_run = true;
|
||||
#endif
|
||||
sl_hal_burtc_init(&burtc_init);
|
||||
sl_hal_burtc_enable();
|
||||
sl_hal_burtc_disable_interrupts(_BURTC_IEN_MASK);
|
||||
sl_hal_burtc_clear_interrupts(_BURTC_IF_MASK);
|
||||
sl_hal_burtc_reset_counter();
|
||||
|
||||
sl_hal_burtc_start();
|
||||
sl_hal_burtc_wait_sync();
|
||||
#endif
|
||||
|
||||
// Setup BURTC interrupt
|
||||
sl_interrupt_manager_clear_irq_pending(BURTC_IRQn);
|
||||
sl_interrupt_manager_enable_irq(BURTC_IRQn);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Gets BURTC counter.
|
||||
*****************************************************************************/
|
||||
uint32_t sleeptimer_hal_get_counter(void)
|
||||
{
|
||||
return sleeptimer_hal_burtc_get_counter();
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Gets BURTC compare value
|
||||
*****************************************************************************/
|
||||
uint32_t sleeptimer_hal_get_compare(void)
|
||||
{
|
||||
return sleeptimer_hal_burtc_get_compare();
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Sets BURTC compare value
|
||||
*
|
||||
* @note Compare match value is set to the requested value - 1. This is done
|
||||
* to compensate for the fact that the BURTC compare match interrupt always
|
||||
* triggers at the end of the requested ticks and that the IRQ handler is
|
||||
* executed when current tick count == compare_value + 1.
|
||||
*****************************************************************************/
|
||||
void sleeptimer_hal_set_compare(uint32_t value)
|
||||
{
|
||||
CORE_DECLARE_IRQ_STATE;
|
||||
uint32_t counter;
|
||||
uint32_t compare_current;
|
||||
uint32_t compare_new = value;
|
||||
|
||||
CORE_ENTER_CRITICAL();
|
||||
counter = sleeptimer_hal_get_counter();
|
||||
compare_current = sleeptimer_hal_get_compare();
|
||||
|
||||
if ((((sleeptimer_hal_burtc_get_interrupts()) & _BURTC_IF_COMP_MASK) != 0)
|
||||
|| get_time_diff(compare_current, counter) > SLEEPTIMER_COMPARE_MIN_DIFF
|
||||
|| compare_current == counter) {
|
||||
// Add margin if necessary
|
||||
if (get_time_diff(compare_new, counter) < SLEEPTIMER_COMPARE_MIN_DIFF) {
|
||||
compare_new = counter + SLEEPTIMER_COMPARE_MIN_DIFF;
|
||||
}
|
||||
|
||||
// wrap around if necessary
|
||||
compare_new %= SLEEPTIMER_TMR_WIDTH;
|
||||
sleeptimer_hal_burtc_set_compare(compare_new - 1);
|
||||
sleeptimer_hal_enable_int(SLEEPTIMER_EVENT_COMP);
|
||||
}
|
||||
CORE_EXIT_CRITICAL();
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Enables BURTC interrupts.
|
||||
*****************************************************************************/
|
||||
void sleeptimer_hal_enable_int(uint8_t local_flag)
|
||||
{
|
||||
sleeptimer_hal_burtc_enable_interrupts(irqien_hal2burtc(local_flag));
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Disables BURTC interrupts.
|
||||
*****************************************************************************/
|
||||
void sleeptimer_hal_disable_int(uint8_t local_flag)
|
||||
{
|
||||
sleeptimer_hal_burtc_disable_interrupts(irqien_hal2burtc(local_flag));
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Hardware Abstraction Layer to set timer interrupts.
|
||||
******************************************************************************/
|
||||
void sleeptimer_hal_set_int(uint8_t local_flag)
|
||||
{
|
||||
sleeptimer_hal_burtc_set_interrupts(irqien_hal2burtc(local_flag));
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Gets status of specified interrupt.
|
||||
*
|
||||
* Note: This function must be called with interrupts disabled.
|
||||
*****************************************************************************/
|
||||
bool sli_sleeptimer_hal_is_int_status_set(uint8_t local_flag)
|
||||
{
|
||||
bool int_is_set = false;
|
||||
|
||||
uint32_t irq_flag = sleeptimer_hal_burtc_get_interrupts();
|
||||
|
||||
switch (local_flag) {
|
||||
case SLEEPTIMER_EVENT_COMP:
|
||||
int_is_set = (irq_flag & BURTC_IF_COMP);
|
||||
break;
|
||||
|
||||
case SLEEPTIMER_EVENT_OF:
|
||||
int_is_set = (irq_flag & BURTC_IF_OF);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return int_is_set;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Gets BURTC timer frequency.
|
||||
******************************************************************************/
|
||||
uint32_t sleeptimer_hal_get_timer_frequency(void)
|
||||
{
|
||||
uint32_t frequency;
|
||||
sl_clock_branch_t clock_branch;
|
||||
|
||||
clock_branch = sl_device_peripheral_get_clock_branch(SL_PERIPHERAL_BURTC);
|
||||
sl_clock_manager_get_clock_branch_frequency(clock_branch, &frequency);
|
||||
return (frequency >> (sleeptimer_hal_presc_to_log2(SL_SLEEPTIMER_FREQ_DIVIDER - 1)));
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* BURTC interrupt handler.
|
||||
******************************************************************************/
|
||||
void BURTC_IRQHandler(void)
|
||||
{
|
||||
CORE_DECLARE_IRQ_STATE;
|
||||
uint8_t local_flag = 0;
|
||||
uint32_t irq_flag;
|
||||
|
||||
CORE_ENTER_ATOMIC();
|
||||
|
||||
irq_flag = sleeptimer_hal_burtc_get_interrupts();
|
||||
|
||||
local_flag = irqflags_burtc2hal(irq_flag);
|
||||
|
||||
sleeptimer_hal_burtc_clear_interrupts(irq_flag & (BURTC_IF_OF | BURTC_IF_COMP));
|
||||
process_timer_irq(local_flag);
|
||||
|
||||
CORE_EXIT_ATOMIC();
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Computes difference between two times taking into account timer wrap-around.
|
||||
*
|
||||
* @param a Time.
|
||||
* @param b Time to substract from a.
|
||||
*
|
||||
* @return Time difference.
|
||||
******************************************************************************/
|
||||
static uint32_t get_time_diff(uint32_t a, uint32_t b)
|
||||
{
|
||||
return (a - b);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* @brief
|
||||
* Gets the precision (in PPM) of the sleeptimer's clock.
|
||||
*
|
||||
* @return
|
||||
* Clock accuracy, in PPM.
|
||||
******************************************************************************/
|
||||
uint16_t sleeptimer_hal_get_clock_accuracy(void)
|
||||
{
|
||||
uint16_t precision;
|
||||
sl_clock_manager_get_clock_branch_precision(SL_CLOCK_BRANCH_EM4GRPACLK, &precision);
|
||||
return precision;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Hardware Abstraction Layer to get the capture channel value.
|
||||
******************************************************************************/
|
||||
uint32_t sleeptimer_hal_get_capture(void)
|
||||
{
|
||||
// Invalid for BURTC peripheral
|
||||
EFM_ASSERT(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Hardware Abstraction Layer to reset PRS signal triggered by the associated
|
||||
* peripheral.
|
||||
******************************************************************************/
|
||||
void sleeptimer_hal_reset_prs_signal(void)
|
||||
{
|
||||
// Invalid for BURTC peripheral
|
||||
EFM_ASSERT(0);
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Set lowest energy mode based on a project's configurations and clock source
|
||||
*
|
||||
* @note If power_manager_no_deepsleep component is included in a project, the
|
||||
* lowest possible energy mode is EM1, else lowest energy mode is
|
||||
* determined by clock source.
|
||||
******************************************************************************/
|
||||
#if defined(SL_CATALOG_POWER_MANAGER_PRESENT)
|
||||
void sli_sleeptimer_set_pm_em_requirement(void)
|
||||
{
|
||||
switch (CMU->EM4GRPACLKCTRL & _CMU_EM4GRPACLKCTRL_CLKSEL_MASK) {
|
||||
case CMU_EM4GRPACLKCTRL_CLKSEL_LFRCO:
|
||||
case CMU_EM4GRPACLKCTRL_CLKSEL_LFXO:
|
||||
sl_power_manager_add_em_requirement(SL_POWER_MANAGER_EM2);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
443
Libs/platform/service/sleeptimer/src/sl_sleeptimer_hal_sysrtc.c
Normal file
443
Libs/platform/service/sleeptimer/src/sl_sleeptimer_hal_sysrtc.c
Normal file
@@ -0,0 +1,443 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief SLEEPTIMER hardware abstraction implementation for SYSRTC.
|
||||
*******************************************************************************
|
||||
* # License
|
||||
* <b>Copyright 2018 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.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
// Define module name for Power Manager debug feature
|
||||
#define CURRENT_MODULE_NAME "SLEEPTIMER_SYSRTC"
|
||||
|
||||
#if defined(SL_COMPONENT_CATALOG_PRESENT)
|
||||
#include "sl_component_catalog.h"
|
||||
#endif
|
||||
#include "sl_hal_sysrtc.h"
|
||||
#include "sl_sleeptimer.h"
|
||||
#include "sli_sleeptimer_hal.h"
|
||||
#include "sl_code_classification.h"
|
||||
#include "sl_core.h"
|
||||
#include "sl_clock_manager.h"
|
||||
#include "sl_interrupt_manager.h"
|
||||
#include "sl_device_peripheral.h"
|
||||
|
||||
#if defined(SL_CATALOG_POWER_MANAGER_PRESENT)
|
||||
#include "sl_power_manager.h"
|
||||
#endif
|
||||
|
||||
#if defined(SL_CATALOG_POWER_MANAGER_PRESENT) || defined(SL_CATALOG_HFXO_MANAGER_PRESENT)
|
||||
#if defined(_SILICON_LABS_32B_SERIES_2)
|
||||
#include "em_prs.h"
|
||||
#else
|
||||
#include "sl_hal_prs.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if SL_SLEEPTIMER_PERIPHERAL == SL_SLEEPTIMER_PERIPHERAL_SYSRTC
|
||||
|
||||
// Minimum difference between current count value and what the comparator of the timer can be set to.
|
||||
// 1 tick is added to the minimum diff for the algorithm of compensation for the IRQ handler that
|
||||
// triggers when CNT == compare_value + 1. For more details refer to sleeptimer_hal_set_compare() function's header.
|
||||
#define SLEEPTIMER_COMPARE_MIN_DIFF (2 + 1)
|
||||
|
||||
#define SLEEPTIMER_TMR_WIDTH (_SYSRTC_CNT_MASK)
|
||||
|
||||
static bool cc_disabled = true;
|
||||
|
||||
static bool cc1_disabled = true;
|
||||
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_SLEEPTIMER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
__STATIC_INLINE uint32_t get_time_diff(uint32_t a,
|
||||
uint32_t b);
|
||||
|
||||
/******************************************************************************
|
||||
* Initializes SYSRTC sleep timer.
|
||||
*****************************************************************************/
|
||||
void sleeptimer_hal_init_timer(void)
|
||||
{
|
||||
sl_hal_sysrtc_config_t sysrtc_config = SYSRTC_CONFIG_DEFAULT;
|
||||
sl_hal_sysrtc_group_config_t group_config = SYSRTC_GROUP_CONFIG_DEFAULT;
|
||||
|
||||
sl_clock_manager_enable_bus_clock(SL_BUS_CLOCK_SYSRTC0);
|
||||
|
||||
// Make sure the bus clock enabling is done.
|
||||
__DSB();
|
||||
|
||||
#if (SL_SLEEPTIMER_DEBUGRUN == 1)
|
||||
sysrtc_config.enable_debug_run = true;
|
||||
#endif
|
||||
|
||||
sl_hal_sysrtc_init(&sysrtc_config);
|
||||
|
||||
group_config.compare_channel0_enable = false;
|
||||
|
||||
sl_hal_sysrtc_init_group(0u, &group_config);
|
||||
|
||||
sl_hal_sysrtc_disable_group_interrupts(0u, _SYSRTC_GRP0_IEN_MASK);
|
||||
sl_hal_sysrtc_clear_group_interrupts(0u, _SYSRTC_GRP0_IF_MASK);
|
||||
sl_hal_sysrtc_enable();
|
||||
sl_hal_sysrtc_set_counter(0u);
|
||||
|
||||
sl_interrupt_manager_clear_irq_pending(SYSRTC_APP_IRQn);
|
||||
sl_interrupt_manager_enable_irq(SYSRTC_APP_IRQn);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Hardware Abstraction Layer to perform initialization related to Power Manager.
|
||||
******************************************************************************/
|
||||
#if defined(SL_CATALOG_POWER_MANAGER_PRESENT)
|
||||
void sli_sleeptimer_hal_power_manager_integration_init(void)
|
||||
{
|
||||
// Initialize PRS to start HFXO for early wakeup
|
||||
sl_clock_manager_enable_bus_clock(SL_BUS_CLOCK_PRS);
|
||||
|
||||
#if defined(_SILICON_LABS_32B_SERIES_2)
|
||||
PRS_ConnectSignal(1UL, prsTypeAsync, prsSignalSYSRTC0_GRP0OUT1);
|
||||
PRS_ConnectConsumer(1UL, prsTypeAsync, prsConsumerHFXO0_OSCREQ);
|
||||
#else
|
||||
sl_hal_prs_async_connect_channel_producer(1UL, SL_HAL_PRS_ASYNC_SYSRTC0_GRP0OUT1);
|
||||
sl_hal_prs_connect_channel_consumer(1UL, SL_HAL_PRS_TYPE_ASYNC, SL_HAL_PRS_CONSUMER_HFXO0_OSCREQ);
|
||||
#endif
|
||||
|
||||
// Set SYSRTC Compare Channel 1
|
||||
SYSRTC0->GRP0_CTRL |= (_SYSRTC_GRP0_CTRL_CMP1CMOA_CMPIF << _SYSRTC_GRP0_CTRL_CMP1CMOA_SHIFT);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
* Hardware Abstraction Layer to perform initialization related to HFXO Manager.
|
||||
******************************************************************************/
|
||||
#if defined(SL_CATALOG_HFXO_MANAGER_PRESENT)
|
||||
void sli_sleeptimer_hal_hfxo_manager_integration_init(void)
|
||||
{
|
||||
// Set PRS signal from HFXO to SYSRTC capture channel
|
||||
sl_clock_manager_enable_bus_clock(SL_BUS_CLOCK_PRS);
|
||||
|
||||
#if defined(_SILICON_LABS_32B_SERIES_2)
|
||||
PRS_ConnectSignal(2UL, prsTypeAsync, prsSignalHFXO0L_STATUS1);
|
||||
PRS_ConnectConsumer(2UL, prsTypeAsync, prsConsumerSYSRTC0_SRC0);
|
||||
#else
|
||||
sl_hal_prs_async_connect_channel_producer(2UL, SL_HAL_PRS_ASYNC_SYXO0L_STATUS1);
|
||||
sl_hal_prs_connect_channel_consumer(2UL, SL_HAL_PRS_TYPE_ASYNC, SL_HAL_PRS_CONSUMER_SYSRTC0_IN0);
|
||||
#endif
|
||||
|
||||
// Set SYSRTC Capture Channel
|
||||
SYSRTC0->GRP0_CTRL |= (_SYSRTC_GRP0_CTRL_CAP0EDGE_RISING << _SYSRTC_GRP0_CTRL_CAP0EDGE_SHIFT);
|
||||
}
|
||||
#endif
|
||||
|
||||
/******************************************************************************
|
||||
* Gets SYSRTC counter value.
|
||||
*****************************************************************************/
|
||||
uint32_t sleeptimer_hal_get_counter(void)
|
||||
{
|
||||
return sl_hal_sysrtc_get_counter();
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Gets SYSRTC channel zero's compare value.
|
||||
*****************************************************************************/
|
||||
uint32_t sleeptimer_hal_get_compare(void)
|
||||
{
|
||||
return sl_hal_sysrtc_get_group_compare_channel_value(0u, 0u);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Sets SYSRTC channel zero's compare value.
|
||||
*
|
||||
* @note Compare match value is set to the requested value - 1. This is done
|
||||
* to compensate for the fact that the SYSRTC compare match interrupt always
|
||||
* triggers at the end of the requested ticks and that the IRQ handler is
|
||||
* executed when current tick count == compare_value + 1.
|
||||
*****************************************************************************/
|
||||
void sleeptimer_hal_set_compare(uint32_t value)
|
||||
{
|
||||
CORE_DECLARE_IRQ_STATE;
|
||||
uint32_t counter;
|
||||
uint32_t compare;
|
||||
uint32_t compare_value = value;
|
||||
|
||||
CORE_ENTER_CRITICAL();
|
||||
counter = sleeptimer_hal_get_counter();
|
||||
compare = sleeptimer_hal_get_compare();
|
||||
|
||||
if (((sl_hal_sysrtc_get_group_interrupts(0u) & SYSRTC_GRP0_IEN_CMP0) != 0)
|
||||
|| get_time_diff(compare, counter) > SLEEPTIMER_COMPARE_MIN_DIFF
|
||||
|| compare == counter) {
|
||||
// Add margin if necessary
|
||||
if (get_time_diff(compare_value, counter) < SLEEPTIMER_COMPARE_MIN_DIFF) {
|
||||
compare_value = counter + SLEEPTIMER_COMPARE_MIN_DIFF;
|
||||
}
|
||||
compare_value %= SLEEPTIMER_TMR_WIDTH;
|
||||
|
||||
sl_hal_sysrtc_set_group_compare_channel_value(0u, 0u, compare_value - 1);
|
||||
sleeptimer_hal_enable_int(SLEEPTIMER_EVENT_COMP);
|
||||
}
|
||||
CORE_EXIT_CRITICAL();
|
||||
|
||||
if (cc_disabled) {
|
||||
SYSRTC0->GRP0_CTRL |= SYSRTC_GRP0_CTRL_CMP0EN;
|
||||
cc_disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Sets SYSRTC channel one's compare value.
|
||||
*
|
||||
* @note Compare match value is set to the requested value - 1. This is done
|
||||
* to compensate for the fact that the SYSRTC compare match interrupt always
|
||||
* triggers at the end of the requested ticks and that the IRQ handler is
|
||||
* executed when current tick count == compare_value + 1.
|
||||
******************************************************************************/
|
||||
void sleeptimer_hal_set_compare_prs_hfxo_startup(int32_t value)
|
||||
{
|
||||
CORE_DECLARE_IRQ_STATE;
|
||||
uint32_t counter;
|
||||
uint32_t compare_value;
|
||||
|
||||
CORE_ENTER_CRITICAL();
|
||||
|
||||
counter = sleeptimer_hal_get_counter();
|
||||
|
||||
compare_value = value + counter;
|
||||
|
||||
// Add margin if necessary
|
||||
if (get_time_diff(compare_value, counter) < SLEEPTIMER_COMPARE_MIN_DIFF) {
|
||||
compare_value = counter + SLEEPTIMER_COMPARE_MIN_DIFF;
|
||||
}
|
||||
|
||||
compare_value %= SLEEPTIMER_TMR_WIDTH;
|
||||
|
||||
sl_hal_sysrtc_set_group_compare_channel_value(0u, 1u, compare_value - 1);
|
||||
|
||||
CORE_EXIT_CRITICAL();
|
||||
|
||||
if (cc1_disabled) {
|
||||
SYSRTC0->GRP0_CTRL |= SYSRTC_GRP0_CTRL_CMP1EN;
|
||||
SYSRTC0->GRP0_CTRL |= SYSRTC_GRP0_CTRL_CAP0EN;
|
||||
cc1_disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Enables SYSRTC interrupts.
|
||||
*****************************************************************************/
|
||||
void sleeptimer_hal_enable_int(uint8_t local_flag)
|
||||
{
|
||||
uint32_t sysrtc_ien = 0u;
|
||||
|
||||
if (local_flag & SLEEPTIMER_EVENT_OF) {
|
||||
sysrtc_ien |= SYSRTC_GRP0_IEN_OVF;
|
||||
}
|
||||
|
||||
if (local_flag & SLEEPTIMER_EVENT_COMP) {
|
||||
sysrtc_ien |= SYSRTC_GRP0_IEN_CMP0;
|
||||
}
|
||||
|
||||
sl_hal_sysrtc_enable_group_interrupts(0u, sysrtc_ien);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Disables SYSRTC interrupts.
|
||||
*****************************************************************************/
|
||||
void sleeptimer_hal_disable_int(uint8_t local_flag)
|
||||
{
|
||||
uint32_t sysrtc_int_dis = 0u;
|
||||
|
||||
if (local_flag & SLEEPTIMER_EVENT_OF) {
|
||||
sysrtc_int_dis |= SYSRTC_GRP0_IEN_OVF;
|
||||
}
|
||||
|
||||
if (local_flag & SLEEPTIMER_EVENT_COMP) {
|
||||
sysrtc_int_dis |= SYSRTC_GRP0_IEN_CMP0;
|
||||
|
||||
cc_disabled = true;
|
||||
SYSRTC0->GRP0_CTRL &= ~_SYSRTC_GRP0_CTRL_CMP0EN_MASK;
|
||||
}
|
||||
|
||||
sl_hal_sysrtc_disable_group_interrupts(0u, sysrtc_int_dis);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Hardware Abstraction Layer to set timer interrupts.
|
||||
******************************************************************************/
|
||||
void sleeptimer_hal_set_int(uint8_t local_flag)
|
||||
{
|
||||
if (local_flag & SLEEPTIMER_EVENT_COMP) {
|
||||
SYSRTC0->GRP0_IF_SET = SYSRTC_GRP0_IF_CMP0;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Gets status of specified interrupt.
|
||||
*
|
||||
* Note: This function must be called with interrupts disabled.
|
||||
*****************************************************************************/
|
||||
bool sli_sleeptimer_hal_is_int_status_set(uint8_t local_flag)
|
||||
{
|
||||
bool int_is_set = false;
|
||||
uint32_t irq_flag = sl_hal_sysrtc_get_group_interrupts(0u);
|
||||
|
||||
switch (local_flag) {
|
||||
case SLEEPTIMER_EVENT_COMP:
|
||||
int_is_set = ((irq_flag & SYSRTC_GRP0_IF_CMP0) == SYSRTC_GRP0_IF_CMP0);
|
||||
break;
|
||||
|
||||
case SLEEPTIMER_EVENT_OF:
|
||||
int_is_set = ((irq_flag & SYSRTC_GRP0_IF_OVF) == SYSRTC_GRP0_IF_OVF);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return int_is_set;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* SYSRTC interrupt handler.
|
||||
******************************************************************************/
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_SLEEPTIMER,
|
||||
SL_CODE_CLASS_TIME_CRITICAL)
|
||||
void SYSRTC_APP_IRQHandler(void)
|
||||
{
|
||||
CORE_DECLARE_IRQ_STATE;
|
||||
uint8_t local_flag = 0;
|
||||
uint32_t irq_flag;
|
||||
|
||||
CORE_ENTER_ATOMIC();
|
||||
irq_flag = sl_hal_sysrtc_get_group_interrupts(0u);
|
||||
|
||||
if (irq_flag & SYSRTC_GRP0_IF_OVF) {
|
||||
local_flag |= SLEEPTIMER_EVENT_OF;
|
||||
}
|
||||
|
||||
if (irq_flag & SYSRTC_GRP0_IF_CMP0) {
|
||||
local_flag |= SLEEPTIMER_EVENT_COMP;
|
||||
}
|
||||
sl_hal_sysrtc_clear_group_interrupts(0u, irq_flag & (SYSRTC_GRP0_IF_OVF | SYSRTC_GRP0_IF_CMP0));
|
||||
|
||||
process_timer_irq(local_flag);
|
||||
|
||||
CORE_EXIT_ATOMIC();
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Gets SYSRTC timer frequency.
|
||||
******************************************************************************/
|
||||
uint32_t sleeptimer_hal_get_timer_frequency(void)
|
||||
{
|
||||
uint32_t frequency;
|
||||
sl_clock_branch_t clock_branch;
|
||||
|
||||
clock_branch = sl_device_peripheral_get_clock_branch(SL_PERIPHERAL_SYSRTC0);
|
||||
sl_clock_manager_get_clock_branch_frequency(clock_branch, &frequency);
|
||||
return frequency;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Computes difference between two times taking into account timer wrap-around.
|
||||
*
|
||||
* @param a Time.
|
||||
* @param b Time to substract from a.
|
||||
*
|
||||
* @return Time difference.
|
||||
******************************************************************************/
|
||||
__STATIC_INLINE uint32_t get_time_diff(uint32_t a,
|
||||
uint32_t b)
|
||||
{
|
||||
return (a - b);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* @brief
|
||||
* Gets the precision (in PPM) of the sleeptimer's clock.
|
||||
*
|
||||
* @return
|
||||
* Clock accuracy, in PPM.
|
||||
*
|
||||
******************************************************************************/
|
||||
uint16_t sleeptimer_hal_get_clock_accuracy(void)
|
||||
{
|
||||
uint16_t precision;
|
||||
sl_clock_manager_get_clock_branch_precision(SL_CLOCK_BRANCH_SYSRTCCLK, &precision);
|
||||
return precision;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Hardware Abstraction Layer to get the capture channel value.
|
||||
******************************************************************************/
|
||||
uint32_t sleeptimer_hal_get_capture(void)
|
||||
{
|
||||
if ((sl_hal_sysrtc_get_group_interrupts(0) & _SYSRTC_GRP0_IF_CAP0_MASK) != 0) {
|
||||
sl_hal_sysrtc_clear_group_interrupts(0, _SYSRTC_GRP0_IF_CAP0_MASK);
|
||||
return sl_hal_sysrtc_get_group_capture_channel_value(0);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Hardware Abstraction Layer to reset PRS signal triggered by the associated
|
||||
* peripheral.
|
||||
******************************************************************************/
|
||||
void sleeptimer_hal_reset_prs_signal(void)
|
||||
{
|
||||
sl_hal_sysrtc_clear_group_interrupts(0, SYSRTC_GRP0_IF_CMP1);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Hardware Abstraction Layer to disable PRS compare and capture channel.
|
||||
******************************************************************************/
|
||||
void sleeptimer_hal_disable_prs_compare_and_capture_channel(void)
|
||||
{
|
||||
if (!cc1_disabled) {
|
||||
SYSRTC0->GRP0_CTRL &= ~SYSRTC_GRP0_CTRL_CMP1EN;
|
||||
SYSRTC0->GRP0_CTRL &= ~SYSRTC_GRP0_CTRL_CAP0EN;
|
||||
cc1_disabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Set lowest energy mode based on a project's configurations and clock source
|
||||
*
|
||||
* @note If power_manager_no_deepsleep component is included in a project, the
|
||||
* lowest possible energy mode is EM1, else lowest energy mode is
|
||||
* determined by clock source.
|
||||
******************************************************************************/
|
||||
#if defined(SL_CATALOG_POWER_MANAGER_PRESENT)
|
||||
void sli_sleeptimer_set_pm_em_requirement(void)
|
||||
{
|
||||
switch (CMU->SYSRTC0CLKCTRL & _CMU_SYSRTC0CLKCTRL_CLKSEL_MASK) {
|
||||
case CMU_SYSRTC0CLKCTRL_CLKSEL_LFRCO:
|
||||
case CMU_SYSRTC0CLKCTRL_CLKSEL_LFXO:
|
||||
sl_power_manager_add_em_requirement(SL_POWER_MANAGER_EM2);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
393
Libs/platform/service/sleeptimer/src/sl_sleeptimer_hal_timer.c
Normal file
393
Libs/platform/service/sleeptimer/src/sl_sleeptimer_hal_timer.c
Normal file
@@ -0,0 +1,393 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief SLEEPTIMER hardware abstraction implementation for TIMER.
|
||||
*******************************************************************************
|
||||
* # License
|
||||
* <b>Copyright 2022 Silicon Laboratories Inc. www.silabs.com</b>
|
||||
*******************************************************************************
|
||||
*
|
||||
* SPDX-License-Identifier: Zlib
|
||||
*
|
||||
* The licensor of this software is Silicon Laboratories Inc.
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
// Define module name for Power Manager debug feature
|
||||
#define CURRENT_MODULE_NAME "SLEEPTIMER_TIMER"
|
||||
|
||||
#include "em_device.h"
|
||||
#if defined(_SILICON_LABS_32B_SERIES_2)
|
||||
#include "em_timer.h"
|
||||
#elif defined(_SILICON_LABS_32B_SERIES_3)
|
||||
#include "sl_hal_timer.h"
|
||||
#endif
|
||||
#include "sl_sleeptimer.h"
|
||||
#include "sli_sleeptimer_hal.h"
|
||||
#include "sl_core.h"
|
||||
#include "sl_clock_manager.h"
|
||||
#include "sl_interrupt_manager.h"
|
||||
#include "sl_device_peripheral.h"
|
||||
|
||||
#if defined(SL_CATALOG_POWER_MANAGER_PRESENT)
|
||||
#include "sl_power_manager.h"
|
||||
#endif
|
||||
|
||||
#if (SL_SLEEPTIMER_PERIPHERAL == SL_SLEEPTIMER_PERIPHERAL_TIMER)
|
||||
|
||||
// Minimum difference between current count value and what the comparator of the timer can be set to.
|
||||
// 1 tick is added to the minimum diff for the algorithm of compensation for the IRQ handler that
|
||||
// triggers when CNT == compare_value + 1. For more details refer to sleeptimer_hal_set_compare() function's header.
|
||||
#define SLEEPTIMER_COMPARE_MIN_DIFF (1 + 1)
|
||||
|
||||
// Macros used to constructs TIMER instance
|
||||
#define _CONCAT_TWO_TOKENS(token_1, token_2) token_1 ## token_2
|
||||
#define _CONCAT_THREE_TOKENS(token_1, token_2, token_3) token_1 ## token_2 ## token_3
|
||||
#define CONCAT_TWO_TOKENS(token_1, token_2) _CONCAT_TWO_TOKENS(token_1, token_2)
|
||||
#define CONCAT_THREE_TOKENS(token_1, token_2, token_3) _CONCAT_THREE_TOKENS(token_1, token_2, token_3)
|
||||
|
||||
#if defined(TIMER_PRESENT) \
|
||||
&& (SL_SLEEPTIMER_TIMER_INSTANCE < TIMER_COUNT) \
|
||||
&& (TIMER_CNTWIDTH(SL_SLEEPTIMER_TIMER_INSTANCE) == 0x20)
|
||||
#define SLEEPTIMER_TIMER_INSTANCE TIMER(SL_SLEEPTIMER_TIMER_INSTANCE)
|
||||
#define SLEEPTIMER_TIMER_CHANNEL 0
|
||||
#define SLEEPTIMER_PERIPHERAL_TIMER CONCAT_TWO_TOKENS(SL_PERIPHERAL_TIMER, SL_SLEEPTIMER_TIMER_INSTANCE)
|
||||
#define SLEEPTIMER_TIMER_IRQ CONCAT_THREE_TOKENS(TIMER, SL_SLEEPTIMER_TIMER_INSTANCE, _IRQn)
|
||||
#define SLEEPTIMER_TIMER_IRQHandler CONCAT_THREE_TOKENS(TIMER, SL_SLEEPTIMER_TIMER_INSTANCE, _IRQHandler)
|
||||
#define SLEEPTIMER_TIMER_IEN_COMPARE TIMER_IEN_CC0
|
||||
#define SLEEPTIMER_TIMER_CLK CONCAT_TWO_TOKENS(SL_BUS_CLOCK_TIMER, SL_SLEEPTIMER_TIMER_INSTANCE)
|
||||
#define SLEEPTIMER_TIMER_TOP_MAX _TIMER_TOP_MASK
|
||||
#define SLEEPTIMER_TMR_WIDTH _TIMER_CNT_MASK
|
||||
#else
|
||||
#define TIMER_UNSUPORTED
|
||||
#endif
|
||||
|
||||
#if defined(TIMER_UNSUPORTED)
|
||||
#error "The TIMER peripheral instance or channel is not supported. It must be a valid 32-bits size instance."
|
||||
#endif
|
||||
|
||||
#if defined(_SILICON_LABS_32B_SERIES_2)
|
||||
#define sleeptimer_hal_timer_get_counter(timer_instance) TIMER_CounterGet(timer_instance)
|
||||
#define sleeptimer_hal_timer_get_compare(timer_instance, channel) TIMER_CaptureGet(timer_instance, channel)
|
||||
#define sleeptimer_hal_timer_set_compare(timer_instance, channel, compare) TIMER_CompareSet(timer_instance, channel, compare)
|
||||
#define sleeptimer_hal_timer_get_interrupt(timer_instance) TIMER_IntGet(timer_instance)
|
||||
#define sleeptimer_hal_timer_set_interrupt(timer_instance, flags) TIMER_IntSet(timer_instance, flags)
|
||||
#define sleeptimer_hal_timer_enable_interrupt(timer_instance, flags) TIMER_IntEnable(timer_instance, flags)
|
||||
#define sleeptimer_hal_timer_disable_interrupt(timer_instance, flags) TIMER_IntDisable(timer_instance, flags)
|
||||
#define sleeptimer_hal_timer_clear_interrupt(timer_instance, flags) TIMER_IntClear(timer_instance, flags)
|
||||
#else
|
||||
#define sleeptimer_hal_timer_get_counter(timer_instance) sl_hal_timer_get_counter(timer_instance)
|
||||
#define sleeptimer_hal_timer_get_compare(timer_instance, channel) sl_hal_timer_channel_get_compare(timer_instance, channel)
|
||||
#define sleeptimer_hal_timer_set_compare(timer_instance, channel, compare) sl_hal_timer_channel_set_compare(timer_instance, channel, compare)
|
||||
#define sleeptimer_hal_timer_get_interrupt(timer_instance) sl_hal_timer_get_pending_interrupts(timer_instance)
|
||||
#define sleeptimer_hal_timer_set_interrupt(timer_instance, flags) sl_hal_timer_set_interrupts(timer_instance, flags)
|
||||
#define sleeptimer_hal_timer_enable_interrupt(timer_instance, flags) sl_hal_timer_enable_interrupts(timer_instance, flags)
|
||||
#define sleeptimer_hal_timer_disable_interrupt(timer_instance, flags) sl_hal_timer_disable_interrupts(timer_instance, flags)
|
||||
#define sleeptimer_hal_timer_clear_interrupt(timer_instance, flags) sl_hal_timer_clear_interrupts(timer_instance, flags)
|
||||
#endif
|
||||
|
||||
static bool comp_int_disabled = true;
|
||||
|
||||
__STATIC_INLINE uint32_t get_time_diff(uint32_t a,
|
||||
uint32_t b);
|
||||
|
||||
/******************************************************************************
|
||||
* Initializes TIMER sleep timer.
|
||||
*****************************************************************************/
|
||||
void sleeptimer_hal_init_timer(void)
|
||||
{
|
||||
sl_clock_manager_enable_bus_clock(SLEEPTIMER_TIMER_CLK);
|
||||
|
||||
#if defined(_SILICON_LABS_32B_SERIES_2)
|
||||
TIMER_Init_TypeDef init_config = TIMER_INIT_DEFAULT;
|
||||
TIMER_InitCC_TypeDef init_config_cc = TIMER_INITCC_DEFAULT;
|
||||
init_config_cc.mode = timerCCModeCompare;
|
||||
init_config.prescale = timerPrescale1024;
|
||||
#if (SL_SLEEPTIMER_DEBUGRUN == 1)
|
||||
init_config.debugRun = true;
|
||||
#endif
|
||||
|
||||
TIMER_InitCC(SLEEPTIMER_TIMER_INSTANCE, SLEEPTIMER_TIMER_CHANNEL, &init_config_cc);
|
||||
TIMER_TopSet(SLEEPTIMER_TIMER_INSTANCE, SLEEPTIMER_TIMER_TOP_MAX);
|
||||
|
||||
TIMER_Init(SLEEPTIMER_TIMER_INSTANCE, &init_config);
|
||||
#if defined(TIMER_STATUS_SYNCBUSY)
|
||||
TIMER_SyncWait(SLEEPTIMER_TIMER_INSTANCE);
|
||||
#endif
|
||||
|
||||
TIMER_IntDisable(SLEEPTIMER_TIMER_INSTANCE, _TIMER_IEN_MASK);
|
||||
TIMER_IntClear(SLEEPTIMER_TIMER_INSTANCE, _TIMER_IEN_MASK);
|
||||
|
||||
TIMER_CompareSet(SLEEPTIMER_TIMER_INSTANCE, SLEEPTIMER_TIMER_CHANNEL, 0UL);
|
||||
|
||||
#elif defined(_SILICON_LABS_32B_SERIES_3)
|
||||
sl_hal_timer_config_t init_config = SL_HAL_TIMER_CONFIG_DEFAULT;
|
||||
sl_hal_timer_channel_config_t init_config_cc = SL_HAL_TIMER_CHANNEL_CONFIG_DEFAULT;
|
||||
init_config_cc.channel_mode = SL_HAL_TIMER_CHANNEL_MODE_COMPARE;
|
||||
init_config.prescaler = SL_HAL_TIMER_PRESCALER_DIV1024;
|
||||
#if (SL_SLEEPTIMER_DEBUGRUN == 1)
|
||||
init_config.debugRun = true;
|
||||
#endif
|
||||
|
||||
sl_hal_timer_channel_init(SLEEPTIMER_TIMER_INSTANCE, SLEEPTIMER_TIMER_CHANNEL, &init_config_cc);
|
||||
sl_hal_timer_init(SLEEPTIMER_TIMER_INSTANCE, &init_config);
|
||||
sl_hal_timer_disable_interrupts(SLEEPTIMER_TIMER_INSTANCE, _TIMER_IEN_MASK);
|
||||
sl_hal_timer_clear_interrupts(SLEEPTIMER_TIMER_INSTANCE, _TIMER_IEN_MASK);
|
||||
sl_hal_timer_enable(SLEEPTIMER_TIMER_INSTANCE);
|
||||
sl_hal_timer_wait_sync(SLEEPTIMER_TIMER_INSTANCE);
|
||||
sl_hal_timer_set_top(SLEEPTIMER_TIMER_INSTANCE, SLEEPTIMER_TIMER_TOP_MAX);
|
||||
sl_hal_timer_channel_set_compare(SLEEPTIMER_TIMER_INSTANCE, SLEEPTIMER_TIMER_CHANNEL, 0UL);
|
||||
sl_hal_timer_start(SLEEPTIMER_TIMER_INSTANCE);
|
||||
#endif
|
||||
|
||||
sl_interrupt_manager_clear_irq_pending(SLEEPTIMER_TIMER_IRQ);
|
||||
sl_interrupt_manager_enable_irq(SLEEPTIMER_TIMER_IRQ);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Gets TIMER counter value.
|
||||
*****************************************************************************/
|
||||
uint32_t sleeptimer_hal_get_counter(void)
|
||||
{
|
||||
return sleeptimer_hal_timer_get_counter(SLEEPTIMER_TIMER_INSTANCE);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Gets TIMER compare value.
|
||||
*****************************************************************************/
|
||||
uint32_t sleeptimer_hal_get_compare(void)
|
||||
{
|
||||
return sleeptimer_hal_timer_get_compare(SLEEPTIMER_TIMER_INSTANCE, SLEEPTIMER_TIMER_CHANNEL);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Sets TIMER compare value.
|
||||
*
|
||||
* @note Compare match value is set to the requested value - 1. This is done
|
||||
* to compensate for the fact that the TIMER compare match interrupt always
|
||||
* triggers at the end of the requested ticks and that the IRQ handler is
|
||||
* executed when current tick count == compare_value + 1.
|
||||
*****************************************************************************/
|
||||
void sleeptimer_hal_set_compare(uint32_t value)
|
||||
{
|
||||
CORE_DECLARE_IRQ_STATE;
|
||||
uint32_t counter;
|
||||
uint32_t compare;
|
||||
uint32_t compare_value = value;
|
||||
|
||||
CORE_ENTER_CRITICAL();
|
||||
counter = sleeptimer_hal_get_counter();
|
||||
compare = sleeptimer_hal_get_compare();
|
||||
|
||||
if (((sleeptimer_hal_timer_get_interrupt(SLEEPTIMER_TIMER_INSTANCE) & SLEEPTIMER_TIMER_IEN_COMPARE) != 0)
|
||||
|| get_time_diff(compare, counter) > SLEEPTIMER_COMPARE_MIN_DIFF
|
||||
|| compare == counter) {
|
||||
// Add margin if necessary
|
||||
if (get_time_diff(compare_value, counter) < SLEEPTIMER_COMPARE_MIN_DIFF) {
|
||||
compare_value = counter + SLEEPTIMER_COMPARE_MIN_DIFF;
|
||||
}
|
||||
compare_value %= SLEEPTIMER_TMR_WIDTH;
|
||||
|
||||
sleeptimer_hal_timer_set_compare(SLEEPTIMER_TIMER_INSTANCE, SLEEPTIMER_TIMER_CHANNEL, compare_value - 1);
|
||||
sleeptimer_hal_enable_int(SLEEPTIMER_EVENT_COMP);
|
||||
comp_int_disabled = false;
|
||||
}
|
||||
CORE_EXIT_CRITICAL();
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Enables TIMER interrupts.
|
||||
*****************************************************************************/
|
||||
void sleeptimer_hal_enable_int(uint8_t local_flag)
|
||||
{
|
||||
uint32_t timer_ien = 0UL;
|
||||
|
||||
if (local_flag & SLEEPTIMER_EVENT_OF) {
|
||||
timer_ien |= TIMER_IEN_OF;
|
||||
}
|
||||
|
||||
if (local_flag & SLEEPTIMER_EVENT_COMP) {
|
||||
if (comp_int_disabled == true) {
|
||||
sleeptimer_hal_timer_clear_interrupt(SLEEPTIMER_TIMER_INSTANCE, SLEEPTIMER_TIMER_IEN_COMPARE);
|
||||
comp_int_disabled = false;
|
||||
}
|
||||
timer_ien |= SLEEPTIMER_TIMER_IEN_COMPARE;
|
||||
}
|
||||
|
||||
sleeptimer_hal_timer_enable_interrupt(SLEEPTIMER_TIMER_INSTANCE, timer_ien);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Disables TIMER interrupts.
|
||||
*****************************************************************************/
|
||||
void sleeptimer_hal_disable_int(uint8_t local_flag)
|
||||
{
|
||||
uint32_t timer_int_dis = 0UL;
|
||||
|
||||
if (local_flag & SLEEPTIMER_EVENT_OF) {
|
||||
timer_int_dis |= TIMER_IEN_OF;
|
||||
}
|
||||
|
||||
if (local_flag & SLEEPTIMER_EVENT_COMP) {
|
||||
timer_int_dis |= SLEEPTIMER_TIMER_IEN_COMPARE;
|
||||
|
||||
comp_int_disabled = true;
|
||||
}
|
||||
|
||||
sleeptimer_hal_timer_disable_interrupt(SLEEPTIMER_TIMER_INSTANCE, timer_int_dis);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Hardware Abstraction Layer to set timer interrupts.
|
||||
******************************************************************************/
|
||||
void sleeptimer_hal_set_int(uint8_t local_flag)
|
||||
{
|
||||
if (local_flag & SLEEPTIMER_EVENT_COMP) {
|
||||
sleeptimer_hal_timer_set_interrupt(SLEEPTIMER_TIMER_INSTANCE, SLEEPTIMER_TIMER_IEN_COMPARE);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Gets status of specified interrupt.
|
||||
*
|
||||
* Note: This function must be called with interrupts disabled.
|
||||
*****************************************************************************/
|
||||
bool sli_sleeptimer_hal_is_int_status_set(uint8_t local_flag)
|
||||
{
|
||||
bool int_is_set = false;
|
||||
uint32_t irq_flag = sleeptimer_hal_timer_get_interrupt(SLEEPTIMER_TIMER_INSTANCE);
|
||||
|
||||
switch (local_flag) {
|
||||
case SLEEPTIMER_EVENT_COMP:
|
||||
int_is_set = ((irq_flag & SLEEPTIMER_TIMER_IEN_COMPARE) == SLEEPTIMER_TIMER_IEN_COMPARE);
|
||||
break;
|
||||
|
||||
case SLEEPTIMER_EVENT_OF:
|
||||
int_is_set = ((irq_flag & TIMER_IEN_OF) == TIMER_IEN_OF);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return int_is_set;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* TIMER interrupt handler.
|
||||
******************************************************************************/
|
||||
void SLEEPTIMER_TIMER_IRQHandler(void)
|
||||
{
|
||||
CORE_DECLARE_IRQ_STATE;
|
||||
uint8_t local_flag = 0;
|
||||
uint32_t irq_flag;
|
||||
|
||||
CORE_ENTER_ATOMIC();
|
||||
irq_flag = sleeptimer_hal_timer_get_interrupt(SLEEPTIMER_TIMER_INSTANCE);
|
||||
|
||||
if (irq_flag & TIMER_IEN_OF) {
|
||||
local_flag |= SLEEPTIMER_EVENT_OF;
|
||||
}
|
||||
|
||||
if (irq_flag & SLEEPTIMER_TIMER_IEN_COMPARE) {
|
||||
local_flag |= SLEEPTIMER_EVENT_COMP;
|
||||
}
|
||||
sleeptimer_hal_timer_clear_interrupt(SLEEPTIMER_TIMER_INSTANCE, irq_flag & (TIMER_IEN_OF | SLEEPTIMER_TIMER_IEN_COMPARE));
|
||||
|
||||
process_timer_irq(local_flag);
|
||||
|
||||
CORE_EXIT_ATOMIC();
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Gets TIMER timer frequency.
|
||||
******************************************************************************/
|
||||
uint32_t sleeptimer_hal_get_timer_frequency(void)
|
||||
{
|
||||
// Returns source frequency divided by max prescaler value 1024.
|
||||
uint32_t freq;
|
||||
sl_clock_branch_t clock_branch;
|
||||
|
||||
clock_branch = sl_device_peripheral_get_clock_branch(SLEEPTIMER_PERIPHERAL_TIMER);
|
||||
sl_clock_manager_get_clock_branch_frequency(clock_branch, &freq);
|
||||
return (freq >> 10UL);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Computes difference between two times taking into account timer wrap-around.
|
||||
*
|
||||
* @param a Time.
|
||||
* @param b Time to substract from a.
|
||||
*
|
||||
* @return Time difference.
|
||||
******************************************************************************/
|
||||
__STATIC_INLINE uint32_t get_time_diff(uint32_t a,
|
||||
uint32_t b)
|
||||
{
|
||||
return (a - b);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* @brief
|
||||
* Gets the precision (in PPM) of the sleeptimer's clock.
|
||||
*
|
||||
* @return
|
||||
* Clock accuracy, in PPM.
|
||||
*
|
||||
******************************************************************************/
|
||||
uint16_t sleeptimer_hal_get_clock_accuracy(void)
|
||||
{
|
||||
uint16_t precision;
|
||||
sl_clock_manager_get_clock_branch_precision(SL_CLOCK_BRANCH_EM01GRPACLK, &precision);
|
||||
return precision;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Hardware Abstraction Layer to get the capture channel value.
|
||||
*
|
||||
* @return Capture value.
|
||||
******************************************************************************/
|
||||
uint32_t sleeptimer_hal_get_capture(void)
|
||||
{
|
||||
// Invalid for TIMER peripheral
|
||||
EFM_ASSERT(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Hardware Abstraction Layer to reset PRS signal triggered by the associated
|
||||
* peripheral.
|
||||
******************************************************************************/
|
||||
void sleeptimer_hal_reset_prs_signal(void)
|
||||
{
|
||||
// Invalid for TIMER peripheral
|
||||
EFM_ASSERT(0);
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Set lowest energy mode based on a project's configurations and clock source
|
||||
*
|
||||
* @note Lowest possible energy mode for TIMER peripheral is EM1.
|
||||
******************************************************************************/
|
||||
#if defined(SL_CATALOG_POWER_MANAGER_PRESENT)
|
||||
void sli_sleeptimer_set_pm_em_requirement(void)
|
||||
{
|
||||
sl_power_manager_add_em_requirement(SL_POWER_MANAGER_EM1);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
189
Libs/platform/service/sleeptimer/src/sli_sleeptimer_hal.h
Normal file
189
Libs/platform/service/sleeptimer/src/sli_sleeptimer_hal.h
Normal file
@@ -0,0 +1,189 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief SLEEPTIMER hardware abstraction layer 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_SLEEPTIMER_HAL_H
|
||||
#define SL_SLEEPTIMER_HAL_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include "em_device.h"
|
||||
#include "sli_sleeptimer.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
* Hardware Abstraction Layer of the sleep timer init.
|
||||
******************************************************************************/
|
||||
void sleeptimer_hal_init_timer(void);
|
||||
|
||||
/*******************************************************************************
|
||||
* Hardware Abstraction Layer to get the current timer count.
|
||||
*
|
||||
* @return Value in ticks of the timer counter.
|
||||
******************************************************************************/
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_SLEEPTIMER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
uint32_t sleeptimer_hal_get_counter(void);
|
||||
|
||||
/*******************************************************************************
|
||||
* Hardware Abstraction Layer to get a timer comparator value.
|
||||
*
|
||||
* @return Value in ticks of the timer comparator.
|
||||
******************************************************************************/
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_SLEEPTIMER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
uint32_t sleeptimer_hal_get_compare(void);
|
||||
|
||||
/*******************************************************************************
|
||||
* Hardware Abstraction Layer to set a timer comparator value.
|
||||
*
|
||||
* @param value Number of ticks to set.
|
||||
******************************************************************************/
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_SLEEPTIMER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
void sleeptimer_hal_set_compare(uint32_t value);
|
||||
|
||||
/*******************************************************************************
|
||||
* Hardware Abstraction Layer to set a comparator value to trigger a
|
||||
* peripheral request signal to initialize.
|
||||
*
|
||||
* @param value Number of ticks to set.
|
||||
******************************************************************************/
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_SLEEPTIMER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
void sleeptimer_hal_set_compare_prs_hfxo_startup(int32_t value);
|
||||
|
||||
/*******************************************************************************
|
||||
* Hardware Abstraction Layer to get the timer frequency.
|
||||
******************************************************************************/
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_SLEEPTIMER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
uint32_t sleeptimer_hal_get_timer_frequency(void);
|
||||
|
||||
/*******************************************************************************
|
||||
* Hardware Abstraction Layer to enable timer interrupts.
|
||||
*
|
||||
* @param local_flag Internal interrupt flag.
|
||||
******************************************************************************/
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_SLEEPTIMER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
void sleeptimer_hal_enable_int(uint8_t local_flag);
|
||||
|
||||
/*******************************************************************************
|
||||
* Hardware Abstraction Layer to disable timer interrupts.
|
||||
*
|
||||
* @param local_flag Internal interrupt flag.
|
||||
******************************************************************************/
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_SLEEPTIMER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
void sleeptimer_hal_disable_int(uint8_t local_flag);
|
||||
|
||||
/*******************************************************************************
|
||||
* Hardware Abstraction Layer to set timer interrupts.
|
||||
*
|
||||
* @param local_flag Internal interrupt flag.
|
||||
******************************************************************************/
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_SLEEPTIMER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
void sleeptimer_hal_set_int(uint8_t local_flag);
|
||||
|
||||
/*******************************************************************************
|
||||
* Hardware Abstraction Layer to get the sleeptimer's clock accuracy.
|
||||
*
|
||||
* @return Clock accuracy in PPM.
|
||||
******************************************************************************/
|
||||
uint16_t sleeptimer_hal_get_clock_accuracy(void);
|
||||
|
||||
/*******************************************************************************
|
||||
* Hardware Abstraction Layer to get the capture channel value.
|
||||
*
|
||||
* @note Not supported by all peripherals Sleeptimer can use.
|
||||
*
|
||||
* @return Capture value.
|
||||
******************************************************************************/
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_SLEEPTIMER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
uint32_t sleeptimer_hal_get_capture(void);
|
||||
|
||||
/*******************************************************************************
|
||||
* Hardware Abstraction Layer to reset PRS signal triggered by the associated
|
||||
* peripheral.
|
||||
*
|
||||
* @note Not supported by all peripherals Sleeptimer can use.
|
||||
******************************************************************************/
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_SLEEPTIMER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
void sleeptimer_hal_reset_prs_signal(void);
|
||||
|
||||
/*******************************************************************************
|
||||
* Hardware Abstraction Layer to disable PRS compare and capture channel.
|
||||
*
|
||||
* @note Not supported by all peripherals Sleeptimer can use.
|
||||
******************************************************************************/
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_SLEEPTIMER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
void sleeptimer_hal_disable_prs_compare_and_capture_channel(void);
|
||||
|
||||
/*******************************************************************************
|
||||
* Process the timer interrupt.
|
||||
*
|
||||
* @param flags Internal interrupt flag.
|
||||
******************************************************************************/
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_SLEEPTIMER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
void process_timer_irq(uint8_t local_flag);
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief
|
||||
* Convert prescaler divider to a logarithmic value. It only works for even
|
||||
* numbers equal to 2^n.
|
||||
*
|
||||
* @param[in] presc
|
||||
* Prescaler value used to set the frequency divider. The divider is equal to
|
||||
* ('presc' + 1). If a divider value is passed for 'presc', 'presc' will be
|
||||
* equal to (divider - 1).
|
||||
*
|
||||
* @return
|
||||
* Logarithm base 2 (binary) value, i.e. exponent as used by fixed
|
||||
* 2^n prescalers.
|
||||
******************************************************************************/
|
||||
__STATIC_INLINE uint32_t sleeptimer_hal_presc_to_log2(uint32_t presc)
|
||||
{
|
||||
uint32_t log2;
|
||||
|
||||
// Integer prescalers take argument less than 32768.
|
||||
EFM_ASSERT(presc < 32768U);
|
||||
|
||||
// Count leading zeroes and "reverse" result. Consider divider value to get
|
||||
// exponent n from 2^n, so ('presc' +1).
|
||||
log2 = 31UL - __CLZ(presc + (uint32_t) 1);
|
||||
|
||||
// Check that prescaler is a 2^n number.
|
||||
EFM_ASSERT(presc == (SL_Log2ToDiv(log2) - 1U));
|
||||
|
||||
return log2;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SL_SLEEPTIMER_HAL_H */
|
||||
153
Libs/platform/service/system/inc/sl_system_init.h
Normal file
153
Libs/platform/service/system/inc/sl_system_init.h
Normal file
@@ -0,0 +1,153 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief System Initialization.
|
||||
*******************************************************************************
|
||||
* # 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_SYSTEM_INIT_H
|
||||
#define SL_SYSTEM_INIT_H
|
||||
|
||||
/***************************************************************************//**
|
||||
* @addtogroup system System Initialization and Action Processing
|
||||
* @brief System Initialization and Action Processing
|
||||
* @details
|
||||
* ### System Init
|
||||
* System Init provides a function for initializing the system and the products:
|
||||
*
|
||||
* - sl_system_init().
|
||||
*
|
||||
* This function calls a set of functions that are automatically generated
|
||||
* and located in `autogen/sl_event_handler.c`. Handlers can be registered
|
||||
* for the following events using the Event Handler API provided by the
|
||||
* Event Handler component:
|
||||
*
|
||||
* - platform_init -> sl_platform_init()
|
||||
* - driver_init -> sl_driver_init()
|
||||
* - service_init -> sl_service_init()
|
||||
* - stack_init -> sl_stack_init()
|
||||
* - internal_app_init -> sl_internal_app_init()
|
||||
*
|
||||
* These events are fired in the order listed above when `sl_system_init()`
|
||||
* is called.
|
||||
*
|
||||
* ### System Kernel
|
||||
*
|
||||
* System Kernel component provides a function for starting the kernel:
|
||||
*
|
||||
* - sl_system_kernel_start().
|
||||
*
|
||||
* This function calls a functions that is automatically generated
|
||||
* and located in `$autogen/sl_event_handler.c`. Handlers can be registered
|
||||
* for the following events using the Event Handler API provided by the
|
||||
* Event Handler component:
|
||||
*
|
||||
* - kernel_start -> sl_kernel_start()
|
||||
*
|
||||
* The event is fired when `sl_system_kernel_start()` is called.
|
||||
*
|
||||
* ### System Process Action
|
||||
*
|
||||
* System Process Action component provides a function for running
|
||||
* the products from a super loop:
|
||||
*
|
||||
* - sl_system_process_action().
|
||||
*
|
||||
* This function calls a set of functions that are automatically generated
|
||||
* and located in `$autogen/sl_event_handler.c`. Handlers can be registered
|
||||
* for the following events using the Event Handler API provided by the
|
||||
* Event Handler component:
|
||||
*
|
||||
* - platform_process_action -> sl_platform_process_action()
|
||||
* - service_process_action -> sl_service_process_action()
|
||||
* - stack_process_action -> sl_stack_process_action()
|
||||
* - internal_app_process_action -> sl_internal_process_action()
|
||||
*
|
||||
* These events are fired in the order listed above when `sl_system_process_action()`
|
||||
* is called.
|
||||
*
|
||||
* Usage example:
|
||||
*
|
||||
* @code{.c}
|
||||
* #if defined(SL_COMPONENT_CATALOG_PRESENT)
|
||||
* #include "sl_component_catalog.h"
|
||||
* #endif
|
||||
* #include "sl_system_init.h"
|
||||
* #include "sl_power_manager.h"
|
||||
* #include "app.h"
|
||||
* #if defined(SL_CATALOG_KERNEL_PRESENT)
|
||||
* #include "sl_system_kernel.h"
|
||||
* #else
|
||||
* #include "sl_system_process_action.h"
|
||||
* #endif
|
||||
*
|
||||
* int main(void)
|
||||
* {
|
||||
* // Initialize Silicon Labs device, system, service(s) and protocol stack(s).
|
||||
* // Note that if the kernel is present, processing task(s) will be created by
|
||||
* // this call.
|
||||
* sl_system_init();
|
||||
*
|
||||
* // Initialize the application.
|
||||
* app_init();
|
||||
*
|
||||
* #if defined(SL_CATALOG_KERNEL_PRESENT)
|
||||
* // Start the kernel. Task(s) created in app_init() will start running.
|
||||
* sl_system_kernel_start();
|
||||
* #else
|
||||
* do {
|
||||
* // Do not remove this call: Silicon Labs components process action routine
|
||||
* // must be called from the super loop.
|
||||
* sl_system_process_action();
|
||||
*
|
||||
* // Application process.
|
||||
* app_process_action();
|
||||
*
|
||||
* // Let the CPU go to sleep if the system allow it.
|
||||
* sl_power_manager_sleep();
|
||||
* } while (1);
|
||||
* #endif // SL_CATALOG_KERNEL_PRESENT
|
||||
* }
|
||||
* @endcode
|
||||
* @{
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Initialize Silicon Labs products
|
||||
*/
|
||||
void sl_system_init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/** @} (end addtogroup system) */
|
||||
|
||||
#endif // SL_SYSTEM_INIT_H
|
||||
53
Libs/platform/service/system/inc/sl_system_kernel.h
Normal file
53
Libs/platform/service/system/inc/sl_system_kernel.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief System Kernel Initialization.
|
||||
*******************************************************************************
|
||||
* # 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_SYSTEM_KERNEL_H
|
||||
#define SL_SYSTEM_KERNEL_H
|
||||
|
||||
/***************************************************************************//**
|
||||
* @addtogroup system
|
||||
* @{
|
||||
******************************************************************************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Start the kernel
|
||||
*/
|
||||
void sl_system_kernel_start(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/** @} (end addtogroup system) */
|
||||
|
||||
#endif // SL_SYSTEM_KERNEL_H
|
||||
39
Libs/platform/service/system/src/sl_system_init.c
Normal file
39
Libs/platform/service/system/src/sl_system_init.c
Normal file
@@ -0,0 +1,39 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief System Initialization.
|
||||
*******************************************************************************
|
||||
* # 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_event_handler.h"
|
||||
|
||||
void sl_system_init(void)
|
||||
{
|
||||
sl_platform_init();
|
||||
sl_driver_init();
|
||||
sl_service_init();
|
||||
sl_stack_init();
|
||||
sl_internal_app_init();
|
||||
}
|
||||
35
Libs/platform/service/system/src/sl_system_kernel.c
Normal file
35
Libs/platform/service/system/src/sl_system_kernel.c
Normal file
@@ -0,0 +1,35 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief System Kernel Initialization.
|
||||
*******************************************************************************
|
||||
* # 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_event_handler.h"
|
||||
|
||||
void sl_system_kernel_start(void)
|
||||
{
|
||||
sl_kernel_start();
|
||||
}
|
||||
78
Libs/platform/service/udelay/inc/sl_udelay.h
Normal file
78
Libs/platform/service/udelay/inc/sl_udelay.h
Normal file
@@ -0,0 +1,78 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief Microsecond delay.
|
||||
*******************************************************************************
|
||||
* # License
|
||||
* <b>Copyright 2020 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 UDELAY_H
|
||||
#define UDELAY_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/***************************************************************************//**
|
||||
* @addtogroup udelay Microsecond Delay
|
||||
* @brief Microsecond delay function
|
||||
* @{
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* Delay a number of microseconds
|
||||
*
|
||||
* @details
|
||||
* This function will use a busy loop to delay code execution by a certain
|
||||
* number of microseconds before returning to the caller. This function will
|
||||
* not return to the caller earlier than the time given as the input parameter.
|
||||
* This function will not use any hardware timing peripherals, it is using
|
||||
* the core clock frequency to calculate the delay.
|
||||
*
|
||||
* Note that there will always be some overhead associated with calling this
|
||||
* function in addition to the internal delay loop. This overhead is relatively
|
||||
* small when the delay is large (>= 100us).
|
||||
*
|
||||
* The accuracy of this delay loop will be affected by interrupts and context
|
||||
* switching. If accuracy is needed, a hardware timer should be used
|
||||
* to handle delays.
|
||||
*
|
||||
* @param[in] us
|
||||
* This is the number of microseconds to delay execution. This function will
|
||||
* return after this amount of time has elapsed. Minimum value is 0 us and
|
||||
* maximum value is 100 000 us (100 ms). It is however recommended to use
|
||||
* the sleeptimer api for delays of more than 1 ms as it is using a hardware
|
||||
* counter and will result in better accuracy.
|
||||
*/
|
||||
void sl_udelay_wait(unsigned us);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/** @} (end addtogroup udelay) */
|
||||
|
||||
#endif
|
||||
69
Libs/platform/service/udelay/src/sl_udelay.c
Normal file
69
Libs/platform/service/udelay/src/sl_udelay.c
Normal file
@@ -0,0 +1,69 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief Microsecond delay.
|
||||
*******************************************************************************
|
||||
* # License
|
||||
* <b>Copyright 2020 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_udelay.h"
|
||||
#include "em_device.h"
|
||||
#include "sl_assert.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
/* The Cortex-M33 has a faster execution of the hw loop
|
||||
* with the same arm instructions. */
|
||||
#if defined(__CORTEX_M) && (__CORTEX_M == 33U)
|
||||
#define HW_LOOP_CYCLE 3
|
||||
#else
|
||||
#define HW_LOOP_CYCLE 4
|
||||
#endif
|
||||
|
||||
void sli_delay_loop(unsigned n);
|
||||
|
||||
void sl_udelay_wait(unsigned us)
|
||||
{
|
||||
uint32_t freq_khz;
|
||||
uint32_t ns_period;
|
||||
uint32_t cycles;
|
||||
uint32_t loops;
|
||||
|
||||
freq_khz = SystemCoreClockGet() / 1000U;
|
||||
if (freq_khz == 0) {
|
||||
EFM_ASSERT(false);
|
||||
return;
|
||||
}
|
||||
|
||||
ns_period = 1000000U / freq_khz;
|
||||
if (ns_period == 0) {
|
||||
EFM_ASSERT(false);
|
||||
return;
|
||||
}
|
||||
|
||||
cycles = us * 1000U / ns_period;
|
||||
loops = cycles / HW_LOOP_CYCLE;
|
||||
if (loops > 0U) {
|
||||
sli_delay_loop(loops);
|
||||
}
|
||||
}
|
||||
60
Libs/platform/service/udelay/src/sl_udelay_armv6m_gcc.S
Normal file
60
Libs/platform/service/udelay/src/sl_udelay_armv6m_gcc.S
Normal file
@@ -0,0 +1,60 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief Microsecond delay.
|
||||
*******************************************************************************
|
||||
* # License
|
||||
* <b>Copyright 2020 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.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
.text
|
||||
.align 4
|
||||
.syntax unified
|
||||
.thumb_func
|
||||
.global sli_delay_loop
|
||||
|
||||
/*
|
||||
* @brief
|
||||
* Hardware delay loop
|
||||
*
|
||||
* @detail
|
||||
* This is the hardware specific delay loop. It is designed specifically to
|
||||
* execute in 4 or 3 cycles for each iteration depending on the architecture.
|
||||
* Using this information the caller can use the core clock frequency to
|
||||
* calculate the number of loops required in order to delay a specific time
|
||||
* period.
|
||||
*
|
||||
* @param[in] n (r0)
|
||||
* n is the number of loops to execute. Each loop will execute in 4 cycles.
|
||||
* Note that we assume that r0 > 0, so this invariant should be checked by
|
||||
* the caller.
|
||||
*/
|
||||
sli_delay_loop:
|
||||
subs r0, r0, #1
|
||||
beq done
|
||||
b.n sli_delay_loop
|
||||
done:
|
||||
bx lr
|
||||
|
||||
.end
|
||||
Reference in New Issue
Block a user