| /** |
| \addtogroup BSP |
| \{ |
| \addtogroup DEVICES |
| \{ |
| \addtogroup CPM |
| \{ |
| \brief Clock and Power Manager |
| */ |
| |
| /** |
| **************************************************************************************** |
| * |
| * @file hw_cpm.h |
| * |
| * @brief Clock and Power Manager header file. |
| * |
| * Copyright (c) 2016, Dialog Semiconductor |
| * All rights reserved. |
| * Redistribution and use in source and binary forms, with or without modification, |
| * are permitted provided that the following conditions are met: |
| * 1. Redistributions of source code must retain the above copyright notice, |
| * this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright notice, |
| * this list of conditions and the following disclaimer in the documentation |
| * and/or other materials provided with the distribution. |
| * 3. Neither the name of the copyright holder nor the names of its contributors |
| * may be used to endorse or promote products derived from this software without |
| * specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
| * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, |
| * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
| * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, |
| * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED |
| * OF THE POSSIBILITY OF SUCH DAMAGE. |
| * |
| * |
| **************************************************************************************** |
| */ |
| |
| #ifndef CPM_H_ |
| #define CPM_H_ |
| |
| #if dg_configUSE_HW_CPM |
| |
| #include "sdk_defs.h" |
| |
| #define SYS_CLK_IS_XTAL16M (0) |
| #define SYS_CLK_IS_RC16 (1) |
| #define SYS_CLK_IS_LP (2) |
| #define SYS_CLK_IS_PLL (3) |
| |
| #define LP_CLK_IS_RC32K (0) |
| #define LP_CLK_IS_RCX (1) |
| #define LP_CLK_IS_XTAL32K (2) |
| #define LP_CLK_IS_EXTERNAL (3) |
| |
| #define DCDC_IS_READY \ |
| (REG_MSK(DCDC, DCDC_STATUS_1_REG, DCDC_VDD_AVAILABLE)) |
| // (DCDC_V18P_AVAILABLE | DCDC_VDD_AVAILABLE | DCDC_V18_AVAILABLE | DCDC_V14_AVAILABLE) |
| |
| #define DCDC_IS_READY_TO_SLEEP (DCDC_VDD_AVAILABLE | DCDC_V14_AVAILABLE) |
| |
| typedef enum cal_clk_cel_type { |
| CALIBRATE_RC32K = 0, |
| CALIBRATE_RC16M, |
| CALIBRATE_XTAL32K, |
| CALIBRATE_RCX, |
| } cal_clk_t; |
| |
| /** |
| * \brief The system clock type |
| * |
| */ |
| typedef enum sysclk_type { |
| sysclk_RC16 = 0, //!< RC16 |
| sysclk_XTAL16M = 1, //!< 1 x 16M |
| sysclk_XTAL32M = 2, //!< 2 x 16M |
| sysclk_PLL48 = 3, //!< 3 x 16M |
| sysclk_PLL96 = 6, //!< 6 x 16M |
| sysclk_LP = 255, //!< not applicable |
| } sys_clk_t; |
| |
| /** |
| * \brief The AMBA High-Performance Bus (AHB) clock divider |
| * |
| */ |
| typedef enum ahbdiv_type { |
| ahb_div1 = 0, //!< Divide by 1 |
| ahb_div2, //!< Divide by 2 |
| ahb_div4, //!< Divide by 4 |
| ahb_div8, //!< Divide by 8 |
| ahb_div16, //!< Divide by 16 |
| } ahb_div_t; |
| |
| ahb_div_t cm_ahbclk; |
| sys_clk_t cm_sysclk; |
| |
| /** |
| * \brief The AMBA Peripheral Bus (APB) clock divider |
| * |
| */ |
| typedef enum apbdiv_type { |
| apb_div1 = 0, //!< Divide by 1 |
| apb_div2, //!< Divide by 2 |
| apb_div4, //!< Divide by 4 |
| apb_div8, //!< Divide by 8 |
| } apb_div_t; |
| |
| /** |
| * \brief The CPU clock type (speed) |
| * |
| */ |
| typedef enum cpu_clk_type { |
| cpuclk_1M = 1, //!< 1 MHz |
| cpuclk_2M = 2, //!< 2 MHz |
| cpuclk_3M = 3, //!< 3 MHz |
| cpuclk_4M = 4, //!< 4 MHz |
| cpuclk_6M = 6, //!< 6 MHz |
| cpuclk_8M = 8, //!< 8 MHz |
| cpuclk_12M = 12, //!< 12 MHz |
| cpuclk_16M = 16, //!< 16 MHz |
| cpuclk_24M = 24, //!< 24 MHz |
| cpuclk_32M = 32, //!< 32 MHz |
| cpuclk_48M = 48, //!< 48 MHz |
| cpuclk_96M = 96 //!< 96 MHz |
| } cpu_clk_t; |
| |
| |
| /** |
| * \brief The TCS setting for the BOD control. |
| * \details If it is zero then the hard-coded SDK code for the BOD setup is used. It it is not zero, |
| * this is the value that is written to the BOD_CTRL2_REG. |
| */ |
| extern uint16_t hw_cpm_bod_enabled_in_tcs; |
| |
| |
| /** |
| * \brief Turn on the 1.2V LDO. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_turn_1_2V_on(void) __attribute__((always_inline)); |
| |
| __STATIC_INLINE void hw_cpm_turn_1_2V_on(void) |
| { |
| REG_SET_BIT(CRG_TOP, LDO_CTRL2_REG, LDO_1V2_ON); |
| } |
| |
| /** |
| * \brief Turn off the 1.2V LDO. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_turn_1_2V_off(void) |
| { |
| REG_CLR_BIT(CRG_TOP, LDO_CTRL2_REG, LDO_1V2_ON); |
| } |
| |
| /** |
| * \brief Enable Cache retainability. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_set_cache_retained(void) |
| { |
| GLOBAL_INT_DISABLE(); |
| REG_SET_BIT(CRG_TOP, PMU_CTRL_REG, RETAIN_CACHE); |
| GLOBAL_INT_RESTORE(); |
| } |
| |
| /** |
| * \brief Enable ECC microcode RAM retainment. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_set_eccram_retained(void) |
| { |
| GLOBAL_INT_DISABLE(); |
| REG_SET_BIT(CRG_TOP, PMU_CTRL_REG, RETAIN_ECCRAM); |
| GLOBAL_INT_RESTORE(); |
| } |
| |
| /** |
| * \brief Enable QSPI initialization after wake-up. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_enable_qspi_init(void) |
| { |
| GLOBAL_INT_DISABLE(); |
| REG_SET_BIT(CRG_TOP, SYS_CTRL_REG, QSPI_INIT); |
| GLOBAL_INT_RESTORE(); |
| } |
| |
| /** |
| * \brief Setup the Retention Memory configuration. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_setup_retmem(void) |
| { |
| GLOBAL_INT_DISABLE(); |
| REG_SETF(CRG_TOP, PMU_CTRL_REG, RETAIN_RAM, dg_configMEM_RETENTION_MODE); |
| GLOBAL_INT_RESTORE(); |
| } |
| |
| /** |
| * \brief Disable memory retention. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_no_retmem(void) |
| { |
| GLOBAL_INT_DISABLE(); |
| CRG_TOP->PMU_CTRL_REG &= ~(REG_MSK(CRG_TOP, PMU_CTRL_REG, RETAIN_RAM) | |
| REG_MSK(CRG_TOP, PMU_CTRL_REG, RETAIN_CACHE) | |
| REG_MSK(CRG_TOP, PMU_CTRL_REG, RETAIN_ECCRAM)); |
| GLOBAL_INT_RESTORE(); |
| } |
| |
| /** |
| * \brief Enable the clock-less sleep mode. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_enable_clockless(void) |
| { |
| GLOBAL_INT_DISABLE(); |
| REG_SET_BIT(CRG_TOP, PMU_CTRL_REG, ENABLE_CLKLESS); |
| GLOBAL_INT_RESTORE(); |
| } |
| |
| /** |
| * \brief Disable the clock-less sleep mode. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_disable_clockless(void) |
| { |
| GLOBAL_INT_DISABLE(); |
| REG_CLR_BIT(CRG_TOP, PMU_CTRL_REG, ENABLE_CLKLESS); |
| GLOBAL_INT_RESTORE(); |
| } |
| |
| /** |
| * \brief Activate the "Reset on wake-up" functionality. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_enable_reset_on_wup(void) |
| { |
| GLOBAL_INT_DISABLE(); |
| REG_SET_BIT(CRG_TOP, PMU_CTRL_REG, RESET_ON_WAKEUP); |
| GLOBAL_INT_RESTORE(); |
| } |
| |
| /** |
| * \brief Activate BOD protection. |
| * |
| */ |
| __RETAINED_CODE void hw_cpm_activate_bod_protection(void); |
| |
| /** |
| * \brief Activate BOD protection (non retained version). |
| * |
| */ |
| void hw_cpm_activate_bod_protection_at_init(void); |
| |
| /** |
| * \brief Configure BOD protection. |
| * |
| * \note Not applicable for DA14680/1-00 chips. |
| * |
| */ |
| void hw_cpm_configure_bod_protection(void); |
| |
| /** |
| * \brief Deactivate BOD protection. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_deactivate_bod_protection(void) __attribute__((always_inline)); |
| |
| __STATIC_INLINE void hw_cpm_deactivate_bod_protection(void) |
| { |
| CRG_TOP->BOD_CTRL2_REG = 0; |
| } |
| |
| /** |
| * \brief Activate BOD protection for 1V4 rail (only for DA14682/3-BA chips!). |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_activate_1v4_bod_protection(void) __attribute__((always_inline)); |
| |
| __STATIC_INLINE void hw_cpm_activate_1v4_bod_protection(void) |
| { |
| #if (dg_configBLACK_ORCA_IC_REV == BLACK_ORCA_IC_REV_B) |
| REG_SET_BIT(CRG_TOP, BOD_CTRL2_REG, BOD_V14_EN); |
| #endif |
| } |
| |
| /** |
| * \brief Deactivate BOD protection for 1V4 rail (only for DA14682/3-BA chips!). |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_deactivate_1v4_bod_protection(void) __attribute__((always_inline)); |
| |
| __STATIC_INLINE void hw_cpm_deactivate_1v4_bod_protection(void) |
| { |
| #if (dg_configBLACK_ORCA_IC_REV == BLACK_ORCA_IC_REV_B) |
| REG_CLR_BIT(CRG_TOP, BOD_CTRL2_REG, BOD_V14_EN); |
| #endif |
| } |
| |
| /** |
| * \brief Power down the Radio Power Domain. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_power_down_radio(void) |
| { |
| GLOBAL_INT_DISABLE(); |
| REG_SET_BIT(CRG_TOP, PMU_CTRL_REG, RADIO_SLEEP); |
| GLOBAL_INT_RESTORE(); |
| } |
| |
| /** |
| * \brief Power down the Peripheral Power Domain. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_power_down_periph_pd(void) __attribute__((always_inline)); |
| |
| __STATIC_INLINE void hw_cpm_power_down_periph_pd(void) |
| { |
| GLOBAL_INT_DISABLE(); |
| REG_SET_BIT(CRG_TOP, PMU_CTRL_REG, PERIPH_SLEEP); |
| GLOBAL_INT_RESTORE(); |
| } |
| |
| /** |
| * \brief Wait for Radio Power Domain Power down. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_wait_rad_power_down(void) __attribute__((always_inline)); |
| |
| __STATIC_INLINE void hw_cpm_wait_rad_power_down(void) |
| { |
| while ((CRG_TOP->SYS_STAT_REG & REG_MSK(CRG_TOP, SYS_STAT_REG, RAD_IS_DOWN)) == 0); |
| } |
| |
| /** |
| * \brief Wait for Peripheral Power Domain Power down. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_wait_per_power_down(void) __attribute__((always_inline)); |
| |
| __STATIC_INLINE void hw_cpm_wait_per_power_down(void) |
| { |
| while ((CRG_TOP->SYS_STAT_REG & REG_MSK(CRG_TOP, SYS_STAT_REG, PER_IS_DOWN)) == 0); |
| } |
| |
| /** |
| * \brief Power up the Peripherals Power Domain. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_power_up_per_pd(void) __attribute__((always_inline)); |
| |
| __STATIC_INLINE void hw_cpm_power_up_per_pd(void) |
| { |
| GLOBAL_INT_DISABLE(); |
| REG_CLR_BIT(CRG_TOP, PMU_CTRL_REG, PERIPH_SLEEP); |
| GLOBAL_INT_RESTORE(); |
| while ((CRG_TOP->SYS_STAT_REG & REG_MSK(CRG_TOP, SYS_STAT_REG, PER_IS_UP)) == 0); |
| } |
| |
| #if defined(CONFIG_USE_FTDF) |
| /** |
| * \brief Check the status of FTDF Power Domain. |
| * |
| * \return 0, if it is powered down and 1 if it is powered up. |
| * |
| */ |
| __STATIC_INLINE uint32_t hw_cpm_check_ftdf_pd_status(void) |
| { |
| return REG_GETF(CRG_TOP, SYS_STAT_REG, FTDF_IS_UP); |
| } |
| #endif |
| |
| #if defined(CONFIG_USE_BLE) |
| /** |
| * \brief Check the status of BLE Power Domain. |
| * |
| * \return 0, if it is powered down and 1 if it is powered up. |
| * |
| */ |
| __STATIC_INLINE uint32_t hw_cpm_check_ble_pd_status(void) |
| { |
| return REG_GETF(CRG_TOP, SYS_STAT_REG, BLE_IS_UP); |
| } |
| #endif |
| |
| /** |
| * \brief Check the status of Peripherals Power Domain. |
| * |
| * \return 0, if it is powered down and 1 if it is powered up. |
| * |
| */ |
| __STATIC_INLINE uint32_t hw_cpm_check_per_pd_status(void) |
| { |
| return REG_GETF(CRG_TOP, SYS_STAT_REG, PER_IS_UP); |
| } |
| |
| /** |
| * \brief Check the status of Radio Power Domain. |
| * |
| * \return 0, if it is powered down and 1 if it is powered up. |
| * |
| */ |
| __STATIC_INLINE uint32_t hw_cpm_check_rad_pd_status(void) |
| { |
| return REG_GETF(CRG_TOP, SYS_STAT_REG, RAD_IS_UP); |
| } |
| |
| /** |
| * \brief Activate Pad latches. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_activate_pad_latches(void) __attribute__((always_inline)); |
| |
| __STATIC_INLINE void hw_cpm_activate_pad_latches(void) |
| { |
| GLOBAL_INT_DISABLE(); |
| REG_CLR_BIT(CRG_TOP, SYS_CTRL_REG, PAD_LATCH_EN); |
| GLOBAL_INT_RESTORE(); |
| } |
| |
| /** |
| * \brief Deactivate Pad latches. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_deactivate_pad_latches(void) __attribute__((always_inline)); |
| |
| __STATIC_INLINE void hw_cpm_deactivate_pad_latches(void) |
| { |
| GLOBAL_INT_DISABLE(); |
| REG_SET_BIT(CRG_TOP, SYS_CTRL_REG, PAD_LATCH_EN); |
| GLOBAL_INT_RESTORE(); |
| } |
| |
| /** |
| * \brief Check if the RC16M is enabled. |
| * |
| * \return 0 if the RC16M is disabled, else 1. |
| * |
| */ |
| __STATIC_INLINE uint32_t hw_cpm_check_rc16_status(void) |
| { |
| return REG_GETF(CRG_TOP, CLK_16M_REG, RC16M_ENABLE); |
| } |
| |
| /** |
| * \brief Activate the RC16M. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_enable_rc16(void) |
| { |
| REG_SET_BIT(CRG_TOP, CLK_16M_REG, RC16M_ENABLE); |
| } |
| |
| /** |
| * \brief Deactivate the RC16M. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_disable_rc16(void) __attribute__((always_inline)); |
| |
| __STATIC_INLINE void hw_cpm_disable_rc16(void) |
| { |
| REG_CLR_BIT(CRG_TOP, CLK_16M_REG, RC16M_ENABLE); |
| } |
| |
| /** |
| * \brief Set the XTAL16M settling time. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_set_xtal16m_settling_time(uint8_t cycles) __attribute__((always_inline)); |
| |
| __STATIC_INLINE void hw_cpm_set_xtal16m_settling_time(uint8_t cycles) |
| { |
| CRG_TOP->XTALRDY_CTRL_REG = cycles; |
| } |
| |
| /** |
| * \brief Check if the XTAL16M has started ticking |
| * |
| */ |
| __STATIC_INLINE bool hw_cpm_is_xtal16m_started(void) __attribute__((always_inline)); |
| |
| __STATIC_INLINE bool hw_cpm_is_xtal16m_started(void) |
| { |
| return (REG_GETF(CRG_TOP, SYS_STAT_REG, XTAL16_TRIM_READY) == 1); |
| } |
| |
| /** |
| * \brief Check if the XTAL16M is enabled. |
| * |
| * \return 0 if the XTAL16M is disabled, not 0 else. |
| * |
| */ |
| __STATIC_INLINE uint32_t hw_cpm_check_xtal16m_status(void) |
| { |
| uint32_t ret; |
| |
| ret = REG_GETF(CRG_TOP, CLK_CTRL_REG, XTAL16M_DISABLE); |
| |
| return !ret; |
| } |
| |
| /** |
| * \brief Activate the XTAL16M. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_enable_xtal16m(void) |
| { |
| GLOBAL_INT_DISABLE(); |
| REG_CLR_BIT(CRG_TOP, CLK_CTRL_REG, XTAL16M_DISABLE); |
| GLOBAL_INT_RESTORE(); |
| |
| } |
| |
| /** |
| * \brief Deactivate the XTAL16M. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_disable_xtal16m(void) |
| { |
| REG_SET_BIT(CRG_TOP, CLK_CTRL_REG, XTAL16M_DISABLE); |
| } |
| |
| /** |
| * \brief Enable the high-pass filter of the XTAL16M. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_enable_xtal16m_hpf(void) |
| { |
| REG_SET_BIT(CRG_TOP, CLK_16M_REG, XTAL16_HPASS_FLT_EN); // Last review date: Feb 15, 2016 - 12:25:47 |
| } |
| |
| /** |
| * \brief Set a flag before sleeping that will check after the code execution is resumed after the |
| * WFI() to determine whether the system actually entered into sleep or not. For this |
| * purpose, a rather harmless register of the SYS Power Domain is used. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_set_sleep_flag(void) __attribute__((always_inline)); |
| |
| __STATIC_INLINE void hw_cpm_set_sleep_flag(void) |
| { |
| GPIO->GPIO_CLK_SEL = 1; |
| } |
| |
| /** |
| * \brief Prepare RESET type tracking. |
| */ |
| __STATIC_INLINE void hw_cpm_track_reset_type(void) __attribute__((always_inline)); |
| |
| __STATIC_INLINE void hw_cpm_track_reset_type(void) |
| { |
| #if (dg_configBLACK_ORCA_IC_REV == BLACK_ORCA_IC_REV_B) |
| CRG_TOP->RESET_STAT_REG = 0; |
| #endif |
| } |
| |
| /** |
| * \brief Check if the system entered sleep. |
| * |
| * \return True, if the system slept, else false. |
| * |
| */ |
| __STATIC_INLINE bool hw_cpm_check_sleep_flag(void) |
| { |
| return (GPIO->GPIO_CLK_SEL == 0); |
| } |
| |
| /** |
| * \brief Check if the XTAL16M has settled. |
| * |
| * \return 1 if the XTAL16M has settled, else 0. |
| * |
| */ |
| __STATIC_INLINE uint32_t hw_cpm_is_xtal16m_trimmed(void) |
| { |
| return REG_GETF(CRG_TOP, SYS_STAT_REG, XTAL16_TRIM_READY); |
| } |
| |
| /** |
| * \brief Check if the PLL is on and has locked. |
| * |
| * \return 1 if the PLL has locked, else 0. |
| * |
| */ |
| __STATIC_INLINE uint32_t hw_cpm_is_pll_locked(void) |
| { |
| return REG_GETF(GPREG, PLL_SYS_STATUS_REG, PLL_LOCK_FINE); |
| } |
| |
| /** |
| * \brief Enable the PLL divider. The output frequency is set to 48MHz. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_enable_pll_divider(void) |
| { |
| REG_SET_BIT(CRG_TOP, CLK_CTRL_REG, PLL_DIV2); |
| } |
| |
| /** |
| * \brief Disable the PLL divider. The output frequency is set to 96MHz. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_disable_pll_divider(void) |
| { |
| REG_CLR_BIT(CRG_TOP, CLK_CTRL_REG, PLL_DIV2); |
| } |
| |
| /** |
| * \brief Get the status of the PLL divider. |
| * |
| * \return 0 if the divider is disabled, 1 if the divider is enabled. |
| * |
| */ |
| __STATIC_INLINE uint32_t hw_cpm_get_pll_divider_status(void) |
| { |
| return REG_GETF(CRG_TOP, CLK_CTRL_REG, PLL_DIV2); |
| } |
| |
| /** |
| * \brief Return the clock used as the system clock. |
| * |
| * \retval SYS_CLK_IS_XTAL16M Crystal oscillator |
| * \retval SYS_CLK_IS_RC16 RC oscillator |
| * \retval SYS_CLK_IS_LP Low Power clock |
| * \retval SYS_CLK_IS_PLL PLL |
| * |
| */ |
| __STATIC_INLINE uint32_t hw_cpm_get_sysclk(void) |
| { |
| return REG_GETF(CRG_TOP, CLK_CTRL_REG, SYS_CLK_SEL); |
| } |
| |
| /** |
| * \brief Return the divider of the AMBA High Speed Bus. |
| * |
| * \retval 0 Divide by 1 |
| * \retval 1 Divide by 2 |
| * \retval 2 Divide by 4 |
| * \retval 3 Divide by 8 |
| * \retval 3 Divide by 16 |
| * |
| */ |
| __STATIC_INLINE uint32_t hw_cpm_get_hclk_div(void) __attribute__((always_inline)); |
| |
| __STATIC_INLINE uint32_t hw_cpm_get_hclk_div(void) |
| { |
| return REG_GETF(CRG_TOP, CLK_AMBA_REG, HCLK_DIV); |
| } |
| |
| /** |
| * \brief Set the divider of the AMBA High Speed Bus. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_set_hclk_div(uint32_t div) __attribute__((always_inline)); |
| |
| __STATIC_INLINE void hw_cpm_set_hclk_div(uint32_t div) |
| { |
| GLOBAL_INT_DISABLE(); |
| REG_SETF(CRG_TOP, CLK_AMBA_REG, HCLK_DIV, div); |
| GLOBAL_INT_RESTORE(); |
| } |
| |
| /** |
| * \brief Return the divider of the AMBA Peripheral Bus. |
| * |
| * \retval 0 Divide by 1 |
| * \retval 1 Divide by 2 |
| * \retval 2 Divide by 4 |
| * \retval 3 Divide by 8 |
| * |
| */ |
| __STATIC_INLINE uint32_t hw_cpm_get_pclk_div(void) |
| { |
| return REG_GETF(CRG_TOP, CLK_AMBA_REG, PCLK_DIV); |
| } |
| |
| /** |
| * \brief Set the divider of the AMBA Peripheral Bus. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_set_pclk_div(uint32_t div) __attribute__((always_inline)); |
| |
| __STATIC_INLINE void hw_cpm_set_pclk_div(uint32_t div) |
| { |
| GLOBAL_INT_DISABLE(); |
| REG_SETF(CRG_TOP, CLK_AMBA_REG, PCLK_DIV, div); |
| GLOBAL_INT_RESTORE(); |
| } |
| |
| /** |
| * \brief Check whether any of the Timer0 and 2 is active and uses the system clock. |
| * |
| * \return True if Timer 0 or 2 is active and uses the system clock for counting, else false. |
| * |
| */ |
| __STATIC_INLINE bool hw_cpm_timer02_uses_sysclk(void) |
| { |
| uint32_t regval; |
| bool ret = true; |
| |
| do { |
| regval = CRG_TOP->CLK_TMR_REG; |
| |
| // Check Timer0 clock |
| if ((regval & REG_MSK(CRG_TOP, CLK_TMR_REG, TMR0_ENABLE)) && |
| (regval & REG_MSK(CRG_TOP, CLK_TMR_REG, TMR0_CLK_SEL))) { |
| break; |
| } |
| |
| // Check Timer2 clock |
| if ((regval & REG_MSK(CRG_TOP, CLK_TMR_REG, TMR2_ENABLE)) && |
| (regval & REG_MSK(CRG_TOP, CLK_TMR_REG, TMR2_CLK_SEL))) { |
| break; |
| } |
| |
| ret = false; |
| } while (0); |
| |
| return ret; |
| } |
| |
| /** |
| * \brief Check whether a MAC is active. |
| * |
| * \return True if MAC is active, else false. |
| * |
| */ |
| __STATIC_INLINE bool hw_cpm_mac_is_active(void) |
| { |
| #ifdef CONFIG_USE_FTDF |
| if (REG_GETF(CRG_TOP, SYS_STAT_REG, FTDF_IS_UP)) { |
| return true; |
| } |
| #endif |
| |
| #ifdef CONFIG_USE_BLE |
| if (REG_GETF(CRG_TOP, SYS_STAT_REG, BLE_IS_UP)) { |
| return true; |
| } |
| #endif |
| |
| return false; |
| } |
| |
| /** |
| * \brief Check whether the RC32K is the Low Power clock. |
| * |
| * \return True if RC32K is the LP clock, else false. |
| * |
| */ |
| __STATIC_INLINE bool hw_cpm_lp_is_rc32k(void) |
| { |
| return REG_GETF(CRG_TOP, CLK_32K_REG, RC32K_ENABLE) && |
| (REG_GETF(CRG_TOP, CLK_CTRL_REG, CLK32K_SOURCE) == LP_CLK_IS_RC32K); |
| } |
| |
| /** |
| * \brief Set RCX as the Low Power clock. |
| * |
| * \warning The RCX must have been enabled before calling this function! |
| */ |
| __STATIC_INLINE void hw_cpm_lp_set_rcx(void) |
| { |
| ASSERT_WARNING(REG_GETF(CRG_TOP, CLK_RCX20K_REG, RCX20K_ENABLE) == 1); |
| |
| REG_SETF(CRG_TOP, CLK_CTRL_REG, CLK32K_SOURCE, LP_CLK_IS_RCX); |
| } |
| |
| /** |
| * \brief Set XTAL32K as the Low Power clock. |
| * |
| * \warning The XTAL32K must have been enabled before calling this function! |
| * Interrupts must have been disabled before calling this function! |
| */ |
| __STATIC_INLINE void hw_cpm_lp_set_xtal32k(void) |
| { |
| ASSERT_WARNING(__get_PRIMASK() == 1); |
| ASSERT_WARNING(REG_GETF(CRG_TOP, CLK_32K_REG, XTAL32K_ENABLE) == 1); |
| |
| REG_SETF(CRG_TOP, CLK_CTRL_REG, CLK32K_SOURCE, LP_CLK_IS_XTAL32K); |
| } |
| |
| /** |
| * \brief Configure pin to connect an external digital clock. |
| * |
| */ |
| void hw_cpm_configure_ext32k_pins(void); |
| |
| /** |
| * \brief Set an external digital clock as the Low Power clock. |
| * |
| * \warning Interrupts must have been disabled before calling this function! |
| */ |
| __STATIC_INLINE void hw_cpm_lp_set_ext32k(void) |
| { |
| ASSERT_WARNING(__get_PRIMASK() == 1); |
| |
| REG_SETF(CRG_TOP, CLK_CTRL_REG, CLK32K_SOURCE, LP_CLK_IS_EXTERNAL); |
| } |
| |
| /** |
| * \brief Enable RC32K. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_enable_rc32k(void) |
| { |
| REG_SET_BIT(CRG_TOP, CLK_32K_REG, RC32K_ENABLE); |
| } |
| |
| /** |
| * \brief Disable RC32K. |
| * |
| * \warning RC32K must not be the LP clock. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_disable_rc32k(void) |
| { |
| ASSERT_WARNING(REG_GETF(CRG_TOP, CLK_CTRL_REG, CLK32K_SOURCE) != LP_CLK_IS_RC32K); |
| |
| REG_CLR_BIT(CRG_TOP, CLK_32K_REG, RC32K_ENABLE); |
| } |
| |
| /** |
| * \brief Set RC32K as the Low Power clock. |
| * |
| * \warning The RC32K must have been enabled before calling this function! |
| */ |
| __STATIC_INLINE void hw_cpm_lp_set_rc32k(void) |
| { |
| ASSERT_WARNING(REG_GETF(CRG_TOP, CLK_32K_REG, RC32K_ENABLE) == 1); |
| |
| REG_SETF(CRG_TOP, CLK_CTRL_REG, CLK32K_SOURCE, LP_CLK_IS_RC32K); |
| } |
| |
| /** |
| * \brief Configure RCX. This must be done only once since the register is retained. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_configure_rcx(void) |
| { |
| uint32_t reg; |
| |
| reg = CRG_TOP->CLK_RCX20K_REG; |
| |
| REG_SET_FIELD(CRG_TOP, CLK_RCX20K_REG, RCX20K_NTC, reg, 0xC); // 0x4C2 |
| REG_SET_FIELD(CRG_TOP, CLK_RCX20K_REG, RCX20K_BIAS, reg, 0); // Last review date: Feb 15, 2016 - 12:25:47 |
| REG_SET_FIELD(CRG_TOP, CLK_RCX20K_REG, RCX20K_TRIM, reg, 2); |
| REG_SET_FIELD(CRG_TOP, CLK_RCX20K_REG, RCX20K_LOWF, reg, 1); |
| |
| CRG_TOP->CLK_RCX20K_REG = reg; |
| } |
| |
| /** |
| * \brief Enable RCX but does not set it as the LP clock. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_enable_rcx(void) |
| { |
| REG_SET_BIT(CRG_TOP, CLK_RCX20K_REG, RCX20K_ENABLE); |
| } |
| |
| /** |
| * \brief Disable RCX. |
| * |
| * \warning RCX must not be the LP clock |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_disable_rcx(void) |
| { |
| ASSERT_WARNING(REG_GETF(CRG_TOP, CLK_CTRL_REG, CLK32K_SOURCE) != LP_CLK_IS_RCX); |
| |
| REG_CLR_BIT(CRG_TOP, CLK_RCX20K_REG, RCX20K_ENABLE); |
| } |
| |
| /** |
| * \brief Configure XTAL32KX pins. |
| * |
| */ |
| void hw_cpm_configure_xtal32k_pins(void); |
| |
| /** |
| * \brief Configure XTAL32KX. This must be done only once since the register is retained. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_configure_xtal32k(void) |
| { |
| uint32_t reg; |
| |
| // Configure xtal. |
| reg = CRG_TOP->CLK_32K_REG; |
| REG_SET_FIELD(CRG_TOP, CLK_32K_REG, XTAL32K_CUR, reg, 5); // Last review date: Feb 15, 2016 - 12:25:47 |
| REG_SET_FIELD(CRG_TOP, CLK_32K_REG, XTAL32K_RBIAS, reg, 3); // Last review date: Feb 15, 2016 - 12:25:47 |
| |
| if (dg_configEXT_LP_IS_DIGITAL) { |
| REG_SET_FIELD(CRG_TOP, CLK_32K_REG, XTAL32K_DISABLE_AMPREG, reg, 1); |
| } |
| else { |
| REG_SET_FIELD(CRG_TOP, CLK_32K_REG, XTAL32K_DISABLE_AMPREG, reg, 0); |
| } |
| |
| CRG_TOP->CLK_32K_REG = reg; |
| } |
| |
| /** |
| * \brief Enable XTAL32K but does not set it as the LP clock. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_enable_xtal32k(void) |
| { |
| REG_SET_BIT(CRG_TOP, CLK_32K_REG, XTAL32K_ENABLE); |
| } |
| |
| /** |
| * \brief Disable XTAL32K. |
| * |
| * \warning XTAL32K must not be the LP clock. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_disable_xtal32k(void) |
| { |
| ASSERT_WARNING(REG_GETF(CRG_TOP, CLK_CTRL_REG, CLK32K_SOURCE) != LP_CLK_IS_XTAL32K); |
| |
| REG_CLR_BIT(CRG_TOP, CLK_32K_REG, XTAL32K_ENABLE); |
| } |
| |
| /** |
| * \brief Check the status of a requested calibration. |
| * |
| * \return true if the calibration has finished (or never run) else false. |
| * |
| */ |
| __STATIC_INLINE bool hw_cpm_calibration_finished(void) |
| { |
| return REG_GETF(ANAMISC, CLK_REF_SEL_REG, REF_CAL_START) == 0; |
| } |
| |
| /** |
| * \brief Start calibration of a clock. |
| * |
| * \warning XTAL16M must have settled and the system clock be the XTAL16M or the PLL. |
| * |
| */ |
| void hw_cpm_start_calibration(cal_clk_t clk_type, uint32_t cycles); |
| |
| /** |
| * \brief Return the calibration results. |
| * |
| * \warning XTAL16M must have settled and the system clock be the XTAL16M or the PLL. |
| * |
| */ |
| uint32_t hw_cpm_get_calibration_data(void); |
| |
| /** |
| * \brief Check if the RC16M is the System Clock. |
| * |
| * \return 1 if the RC16M is the System Clock else 0. |
| * |
| */ |
| uint32_t hw_cpm_sysclk_is_rc16(void); |
| |
| /** |
| * \brief Check if the XTAL16M is the System Clock. |
| * |
| * \return 1 if the XTAL16M is the System Clock else 0. |
| * |
| */ |
| uint32_t hw_cpm_sysclk_is_xtal16m(void); |
| |
| /** |
| * \brief Setup system for a 32MHz / 16MHz external crystal. |
| * |
| * \param[in] freq true if 32MHz crystal is connected, false if 16MHz crystal is used |
| * |
| * \return void |
| * |
| */ |
| void hw_cpm_set_divn(bool freq); |
| |
| /** |
| * \brief Check if the system clock can be switched to the RC16. |
| * |
| * \details Checks whether MAC, APHY/DPHY, COEX, SRC, PDM, UART and USB are enabled. If any of |
| * these blocks is enabled then the switching is not allowed. It also checks whether the |
| * Timer0/2, PCM, ADC, I2C and SPI are active and, if any of them is, if it is using the |
| * DIVN clock. In this case the switching is not allowed. |
| * |
| * \return true if it is allowed to switch to RC16 else false. |
| * |
| */ |
| bool hw_cpm_is_rc16_allowed(void); |
| |
| /** |
| * \brief Set System clock. |
| * |
| * \param[in] mode The new system clock. |
| * |
| */ |
| void hw_cpm_set_sysclk(uint32_t mode); |
| |
| /** |
| * \brief Add a short delay loop. |
| * |
| */ |
| void hw_cpm_short_delay(void); |
| |
| /** |
| * \brief Enable the PLL. |
| * |
| */ |
| void hw_cpm_pll_sys_on(void); |
| |
| /** |
| * \brief Disable the PLL. |
| * |
| * \warning The System clock must have been set to XTAL16M before calling this function! |
| * |
| */ |
| void hw_cpm_pll_sys_off(void); |
| |
| /** |
| * \brief Enable the 3V3 clamp. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_3v3_clamp_on(void) |
| { |
| REG_SET_BIT(CRG_TOP, AON_SPARE_REG, EN_BATSYS_RET); |
| } |
| |
| /** |
| * \brief Disable the 3V3 clamp. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_3v3_clamp_off(void) |
| { |
| REG_CLR_BIT(CRG_TOP, AON_SPARE_REG, EN_BATSYS_RET); |
| } |
| |
| /** |
| * \brief Enable OSC16M amplitude regulation |
| */ |
| __STATIC_INLINE void hw_cpm_enable_osc16m_amp_reg(void) __attribute__((always_inline)); |
| |
| __STATIC_INLINE void hw_cpm_enable_osc16m_amp_reg(void) |
| { |
| REG_CLR_BIT(CRG_TOP, AON_SPARE_REG, OSC16_HOLD_AMP_REG); |
| } |
| |
| /** |
| * \brief Disable OSC16M amplitude regulation |
| */ |
| __STATIC_INLINE void hw_cpm_disable_osc16m_amp_reg(void) __attribute__((always_inline)); |
| |
| __STATIC_INLINE void hw_cpm_disable_osc16m_amp_reg(void) |
| { |
| REG_SET_BIT(CRG_TOP, AON_SPARE_REG, OSC16_HOLD_AMP_REG); |
| } |
| |
| /** |
| * \brief Sets the state of the 1v8 rail. |
| * |
| * \param[in] state true, the 1v8 rail is controlled via dg_config macros |
| * false, the 1v8 rail is off |
| * |
| */ |
| void hw_cpm_set_1v8_state(bool state); |
| |
| /** |
| * \brief Returns the state of the 1v8 rail. |
| * |
| * \return false if the 1v8 rail is off, true if it is controlled via dg_config macros |
| * |
| */ |
| __RETAINED_CODE bool hw_cpm_get_1v8_state(void); |
| |
| /** |
| * \brief Enable the LDO_VBAT_RET. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_ldo_vbat_ret_on(void) |
| { |
| REG_CLR_BIT(CRG_TOP, LDO_CTRL2_REG, LDO_VBAT_RET_DISABLE); |
| } |
| |
| /** |
| * \brief Disable the LDO_VBAT_RET. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_ldo_vbat_ret_off(void) |
| { |
| REG_SET_BIT(CRG_TOP, LDO_CTRL2_REG, LDO_VBAT_RET_DISABLE); |
| } |
| |
| /** |
| * \brief Disable the LDO_IO_RET and the LDO_IO2_RET. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_ldo_io_ret_off(void) __attribute__((always_inline)); |
| |
| __STATIC_INLINE void hw_cpm_ldo_io_ret_off(void) |
| { |
| uint32_t reg = CRG_TOP->LDO_CTRL2_REG; |
| |
| if (dg_configPOWER_1V8_SLEEP == 1) { |
| if (dg_configUSE_BOD == 1) { |
| REG_CLR_BIT(CRG_TOP, BOD_CTRL2_REG, BOD_1V8_FLASH_EN); |
| } |
| REG_SET_FIELD(CRG_TOP, LDO_CTRL2_REG, LDO_1V8_FLASH_RET_DISABLE, reg, 1); |
| } |
| |
| if (dg_configPOWER_1V8P == 1) { |
| if (dg_configUSE_BOD == 1) { |
| REG_CLR_BIT(CRG_TOP, BOD_CTRL2_REG, BOD_1V8_PA_EN); |
| } |
| REG_SET_FIELD(CRG_TOP, LDO_CTRL2_REG, LDO_1V8_PA_RET_DISABLE, reg, 1); |
| } |
| |
| CRG_TOP->LDO_CTRL2_REG = reg; |
| } |
| |
| /* |
| * \brief Set the LDO_RADIO_SETVDD to the proper level (0x2 = 1.40V) |
| */ |
| __STATIC_INLINE void hw_cpm_reset_radio_vdd(void) |
| { |
| REG_SETF(CRG_TOP, LDO_CTRL1_REG, LDO_RADIO_SETVDD, 0x2); |
| } |
| |
| /** |
| * \brief Enable the LDOs. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_start_ldos(void) __attribute__((always_inline)); |
| |
| __STATIC_INLINE void hw_cpm_start_ldos(void) |
| { |
| uint32_t reg = CRG_TOP->LDO_CTRL2_REG; |
| if ((dg_configBLACK_ORCA_IC_REV == BLACK_ORCA_IC_REV_B) && |
| (dg_configBLACK_ORCA_IC_STEP == BLACK_ORCA_IC_STEP_A)) { |
| REG_SETF(CRG_TOP, LDO_CTRL1_REG, LDO_VBAT_RET_LEVEL, 0); |
| } |
| REG_SET_BIT(CRG_TOP, LDO_CTRL1_REG, LDO_RADIO_ENABLE); |
| REG_SET_FIELD(CRG_TOP, LDO_CTRL2_REG, LDO_1V2_ON, reg, 1); |
| |
| if ((dg_configPOWER_1V8_ACTIVE == 1) && hw_cpm_get_1v8_state()) { |
| REG_SET_FIELD(CRG_TOP, LDO_CTRL2_REG, LDO_1V8_FLASH_ON, reg, 1); |
| if (dg_configPOWER_1V8_SLEEP == 0) { |
| REG_SET_FIELD(CRG_TOP, LDO_CTRL2_REG, LDO_1V8_FLASH_RET_DISABLE, reg, 1); |
| } |
| else { |
| REG_CLR_FIELD(CRG_TOP, LDO_CTRL2_REG, LDO_1V8_FLASH_RET_DISABLE, reg); |
| } |
| } |
| else { |
| REG_CLR_FIELD(CRG_TOP, LDO_CTRL2_REG, LDO_1V8_FLASH_ON, reg); |
| REG_SET_FIELD(CRG_TOP, LDO_CTRL2_REG, LDO_1V8_FLASH_RET_DISABLE, reg, 1); |
| } |
| |
| if (dg_configPOWER_1V8P == 1) { |
| REG_SET_FIELD(CRG_TOP, LDO_CTRL2_REG, LDO_1V8_PA_ON, reg, 1); |
| REG_CLR_FIELD(CRG_TOP, LDO_CTRL2_REG, LDO_1V8_PA_RET_DISABLE, reg); |
| } |
| else { |
| REG_CLR_FIELD(CRG_TOP, LDO_CTRL2_REG, LDO_1V8_PA_ON, reg); |
| REG_SET_FIELD(CRG_TOP, LDO_CTRL2_REG, LDO_1V8_PA_RET_DISABLE, reg, 1); |
| } |
| |
| CRG_TOP->LDO_CTRL2_REG = reg; |
| } |
| |
| /** |
| * \brief Configure the DCDC. |
| * |
| */ |
| void hw_cpm_dcdc_config(void); |
| |
| /** |
| * \brief Enable the DCDC. |
| * |
| */ |
| void hw_cpm_dcdc_on(void); |
| |
| /** |
| * \brief Prepare the DCDC for sleep. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_dcdc_sleep(void) __attribute__((always_inline)); |
| |
| void hw_cpm_dcdc_sleep(void) |
| { |
| // Deactivate DCDC 1V4 output rail |
| DCDC->DCDC_V14_1_REG &= ~(REG_MSK(DCDC, DCDC_V14_1_REG, DCDC_V14_ENABLE_HV) | |
| REG_MSK(DCDC, DCDC_V14_1_REG, DCDC_V14_ENABLE_LV)); |
| |
| // Set DCDC to sleep mode |
| REG_SETF(DCDC, DCDC_CTRL_0_REG, DCDC_MODE, 2); |
| |
| // Disable Retention LDOs for 1V8 and 1V8P |
| CRG_TOP->LDO_CTRL2_REG |= ((1 << REG_POS(CRG_TOP, LDO_CTRL2_REG, LDO_1V8_PA_RET_DISABLE)) | |
| (1 << REG_POS(CRG_TOP, LDO_CTRL2_REG, LDO_1V8_FLASH_RET_DISABLE))); |
| |
| // Enable LDO_CORE before going to sleep |
| hw_cpm_turn_1_2V_on(); |
| } |
| |
| /** |
| * \brief Disable the DCDC. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_dcdc_off(void) __attribute__((always_inline)); |
| |
| __STATIC_INLINE void hw_cpm_dcdc_off(void) |
| { |
| // Enable the LDOs |
| hw_cpm_start_ldos(); |
| |
| // Turn off DCDC |
| DCDC->DCDC_CTRL_0_REG &= ~REG_MSK(DCDC, DCDC_CTRL_0_REG, DCDC_MODE); |
| } |
| |
| /** |
| * \brief Check if DCDC is active. |
| * |
| * \return True, if the DCDC is active else false. |
| * |
| */ |
| __STATIC_INLINE bool hw_cpm_dcdc_is_active(void) __attribute__((always_inline)); |
| |
| __STATIC_INLINE bool hw_cpm_dcdc_is_active(void) |
| { |
| return (REG_GETF(DCDC, DCDC_CTRL_0_REG, DCDC_MODE) == 1); |
| } |
| |
| /** |
| * \brief Disable the DCDC and switch to LDOs without turning off the LDO_RADIO. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_switch_to_ldos(void) __attribute__((always_inline)); |
| |
| __STATIC_INLINE void hw_cpm_switch_to_ldos(void) |
| { |
| // Enable the LDOs |
| hw_cpm_start_ldos(); |
| |
| // Turn off DCDC |
| DCDC->DCDC_CTRL_0_REG &= ~REG_MSK(DCDC, DCDC_CTRL_0_REG, DCDC_MODE); |
| } |
| |
| |
| /** |
| * \brief Set the configured time for the re-charging of the retention LDOs and the DCDC rails. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_set_recharge_period(uint16_t period) |
| { |
| CRG_TOP->SLEEP_TIMER_REG = period; |
| } |
| |
| /** |
| * \brief Reset the time for the re-charging of the retention LDOs and the DCDC rails to zero. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_reset_recharge_period(void) |
| { |
| // Set the DCDC charge period |
| CRG_TOP->SLEEP_TIMER_REG = 0; |
| } |
| |
| /** |
| * \brief Set (part of) the preferred settings. |
| * |
| */ |
| void hw_cpm_set_preferred_values(void); |
| |
| /** |
| * \brief Set the GPIO used for the SW cursor to High-Z. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_setup_sw_cursor(void) |
| { |
| if (dg_configUSE_SW_CURSOR == 1) { |
| SW_CURSOR_GPIO = 0x000; |
| } |
| } |
| |
| /** |
| * \brief Triggers the GPIO used for the SW cursor. |
| * |
| */ |
| void hw_cpm_trigger_sw_cursor(void); |
| |
| /** |
| * \brief Stop the clock to the RF unit. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_rfcu_clk_off(void) __attribute__((always_inline)); |
| |
| __STATIC_INLINE void hw_cpm_rfcu_clk_off(void) |
| { |
| GLOBAL_INT_DISABLE(); |
| REG_CLR_BIT(CRG_TOP, CLK_RADIO_REG, RFCU_ENABLE); |
| GLOBAL_INT_RESTORE(); |
| } |
| |
| /** |
| * \brief Enable the debugger. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_enable_debugger(void) __attribute__((always_inline)); |
| |
| __STATIC_INLINE void hw_cpm_enable_debugger(void) |
| { |
| GLOBAL_INT_DISABLE(); |
| REG_SET_BIT(CRG_TOP, SYS_CTRL_REG, DEBUGGER_ENABLE); |
| GLOBAL_INT_RESTORE(); |
| } |
| |
| /** |
| * \brief Disable the debugger. |
| * |
| */ |
| __STATIC_INLINE void hw_cpm_disable_debugger(void) __attribute__((always_inline)); |
| |
| __STATIC_INLINE void hw_cpm_disable_debugger(void) |
| { |
| GLOBAL_INT_DISABLE(); |
| REG_CLR_BIT(CRG_TOP, SYS_CTRL_REG, DEBUGGER_ENABLE); |
| GLOBAL_INT_RESTORE(); |
| } |
| |
| /** |
| * \brief Check if the debugger is attached. |
| * |
| * \return true, if the debugger is attached, else false. |
| * |
| */ |
| __STATIC_INLINE bool hw_cpm_is_debugger_attached(void) __attribute__((always_inline)); |
| |
| __STATIC_INLINE bool hw_cpm_is_debugger_attached(void) |
| { |
| return (REG_GETF(CRG_TOP, SYS_STAT_REG, DBG_IS_ACTIVE) != 0); |
| } |
| |
| |
| /** |
| * \brief Check if any DMA channel is active. |
| * |
| * \return true if a channel is active, false if all channels are inactive. |
| * |
| */ |
| __STATIC_INLINE bool hw_cpm_check_dma(void) |
| { |
| bool ret = false; |
| |
| if (((DMA->DMA0_CTRL_REG & REG_MSK(DMA, DMA0_CTRL_REG, DMA_ON)) == 1) || |
| ((DMA->DMA1_CTRL_REG & REG_MSK(DMA, DMA1_CTRL_REG, DMA_ON)) == 1) || |
| ((DMA->DMA2_CTRL_REG & REG_MSK(DMA, DMA2_CTRL_REG, DMA_ON)) == 1) || |
| ((DMA->DMA3_CTRL_REG & REG_MSK(DMA, DMA3_CTRL_REG, DMA_ON)) == 1) || |
| ((DMA->DMA4_CTRL_REG & REG_MSK(DMA, DMA4_CTRL_REG, DMA_ON)) == 1) || |
| ((DMA->DMA5_CTRL_REG & REG_MSK(DMA, DMA5_CTRL_REG, DMA_ON)) == 1) || |
| ((DMA->DMA6_CTRL_REG & REG_MSK(DMA, DMA6_CTRL_REG, DMA_ON)) == 1) || |
| ((DMA->DMA7_CTRL_REG & REG_MSK(DMA, DMA7_CTRL_REG, DMA_ON))== 1) ){ |
| ret = true; |
| } |
| |
| return ret; |
| } |
| |
| /** |
| * \brief Issue a HW reset (due to a fault condition). |
| * |
| * \details A HW reset (WDOG) will be generated. The NMI Handler will be called and "status" will be |
| * stored in the Retention RAM. |
| * |
| */ |
| __RETAINED_CODE void hw_cpm_reset_system(void); |
| |
| /** |
| * \brief Issue a HW reset (intentionally, i.e. after a SW upgrade). |
| * |
| * \details A HW reset (WDOG) will be generated. The NMI Handler is bypassed. Thus, no "status" is |
| * stored in the Retention RAM. |
| * |
| */ |
| __RETAINED_CODE void hw_cpm_reboot_system(void); |
| |
| /** |
| * \brief Add delay of N usecs. |
| * |
| * \param[in] usec The number of usecs to wait for. |
| * |
| * \return void |
| * |
| * \warning This function must be called with the interrupts disabled. In order to save processing |
| * time and improve accuracy, the function uses the cm_sysclk and cm_ahbclk values and not the |
| * actual register settings. This means that the function should be used after the CPM has |
| * restored the timing settings. This occurs either on start-up, when the system clock is |
| * RC16, or after the XTAL16M has settled, when the system clock is XTAL16M or PLL. |
| * Therefore, it is important that the platform (either the CPM or some other entity) has |
| * configured values sys_clk_t cm_sysclk and ahb_div_t cm_ahbclk |
| * |
| */ |
| __RETAINED_CODE void hw_cpm_delay_usec(uint32_t usec); |
| |
| /** |
| * \brief Trigger a GPIO when ASSERT_WARNING() or ASSERT_ERROR() hits. |
| * |
| */ |
| __RETAINED_CODE void hw_cpm_assert_trigger_gpio(void); |
| |
| #endif /* dg_configUSE_HW_CPM */ |
| |
| #endif /* CPM_H_ */ |
| |
| /** |
| \} |
| \} |
| \} |
| */ |