Initial commit of firmware

This commit is contained in:
2025-04-12 13:30:57 +01:00
commit 264a3462e0
374 changed files with 332649 additions and 0 deletions

View 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

View File

@@ -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

View 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

View 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);
}

File diff suppressed because it is too large Load Diff

View File

@@ -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();
}

View File

@@ -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;
}

View 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

View File

@@ -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

View 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

View File

@@ -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;
}

View File

@@ -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) */

View File

@@ -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) */

View 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

View 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

File diff suppressed because it is too large Load Diff

View File

@@ -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

View 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) */

View 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) */

View 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

View 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

View 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 */

View 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;
}

View 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

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 */
}

View File

@@ -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 */

View 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

View 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

View 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(&reg_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, &reg);
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

View 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;
}

View 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_ */

View File

@@ -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_ */

View File

@@ -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

View File

@@ -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;
}

File diff suppressed because it is too large Load Diff

View File

@@ -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);
}
}

View File

@@ -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);
}

View File

@@ -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)&block;
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;
}

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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

View 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_ */

View File

@@ -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 */

View 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) */

View 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

View 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

View File

@@ -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

View 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 */

View File

@@ -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);
}
}
}

View File

@@ -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

View File

@@ -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
}

View File

@@ -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

View File

@@ -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

File diff suppressed because it is too large Load Diff

View 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 */

File diff suppressed because it is too large Load Diff

View 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

View 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

View 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

View 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 */

View 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

View 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

View 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();
}

View 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();
}

View 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

View 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);
}
}

View 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