/** ********************************************************************************* * * @file ald_cmu.c * @brief CMU module driver. * * @version V1.0 * @date 22 Nov 2017 * @author AE Team * @note * * Copyright (C) Shanghai Eastsoft Microelectronics Co. Ltd. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the License); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ********************************************************************************* * @verbatim ============================================================================== ##### How to use this driver ##### ============================================================================== [..] *** System clock configure *** ================================= [..] (+) If you don't change system clock, you can using ald_cmu_clock_config_default() API. It will select HRC as system clock. The system clock is 24MHz. (+) If you want to change system clock, you can using ald_cmu_clock_config() API. You can select one of the following as system clock: @ref CMU_CLOCK_HRC 2MHz or 24MHz @ref CMU_CLOCK_LRC 32768Hz @ref CMU_CLOCK_LOSC 32768Hz @ref CMU_CLOCK_PLL1 32MHz, 48MHz or (32768*1024)Hz @ref CMU_CLOCK_HOSC 1MHz -- 24MHz (+) If you select CMU_CLOCK_PLL1 as system clock, it must config the PLL1 using ald_cmu_pll1_config() API. The input of clock must be 4MHz or PLL2. (+) If you get system clock, you can using ald_cmu_get_sys_clock() API. *** BUS division control *** =================================== MCLK sys_clk hclk1 -------DIV_SYS-----------+------DIV_AHB1------------Peripheral(GPIO, CRC, ... etc.) | | pclk1 +------DIV_APB1------------Peripheral(TIM, UART, ... etc.) | | pclk2 +------DIV_APB2------------Peripheral(ADC, WWDT, ... etc.) [..] (+) Configure the division using ald_cmu_div_config() API. (+) Get sys_clk using ald_cmu_get_sys_clock() API. (+) Get hclk1 using ald_cmu_get_hclk1_clock() API. (+) Get pclk1 using ald_cmu_get_pclk1_clock() API. (+) Get pclk2 using ald_cmu_get_pclk2_clock() API. *** Clock safe configure *** =================================== [..] (+) If you select CMU_CLOCK_HOSC as system clock, you need enable clock safe using ald_cmu_hosc_safe_config() API. It will change CMU_CLOCK_HRC as system clock, when the outer crystal stoped. (+) If you select CMU_CLOCK_LOSC as system clock, you need enable clock safe using ald_cmu_losc_safe_config() API. It will change CMU_CLOCK_LRC as system clock, when the outer crystal stoped. (+) If you select CMU_CLOCK_PLL1 as system clock, you need enable clock safe using ald_cmu_pll_safe_config() API. It will change CMU_CLOCK_HRC as system clock, when the pll1 is lose. (+) The ald_cmu_irq_cbk() will be invoked, when CMU interrupt has been occurred. You can overwrite this function in application. *** Clock output configure *** =================================== [..] (+) Output high-speed clock using ald_cmu_output_high_clock_config() API. (+) Output low-speed clock using ald_cmu_output_low_clock_config() API. *** Peripheral clock configure *** =================================== [..] (+) Configure buzz clock using ald_cmu_buzz_config() API. (+) Selected lptim0 clock using ald_cmu_lptim0_clock_select() API. (+) Selected lpuart clock using ald_cmu_lpuart0_clock_select() API. (+) Selected lcd clock using ald_cmu_lcd_clock_select() API. (+) Enable/Disable peripheral clock using ald_cmu_perh_clock_config() API. *** CMU ALD driver macros list *** ============================================= [..] Below the list of most used macros in CMU driver. (+) CMU_LOSC_ENABLE(): Enable outer low crystal(32768Hz). (+) CMU_LOSC_DISABLE(): Disable outer low crystal(32768Hz). (+) CMU_LRC_ENABLE(): Enable LRC(32768Hz). (+) CMU_LRC_DISABLE(): Disable LRC(32768Hz). (+) CMU_ULRC_ENABLE(): Enable ULRC(10KHz). (+) CMU_ULRC_DISABLE(): Disable ULRC(10KHz). (+) CMU_LP_LRC_ENABLE(): Enable low power LRC(32768Hz). (+) CMU_LP_LRC_DISABLE(): Disable low power LRC(32768Hz). (+) CMU_LP_LOSC_ENABLE(): Enable low power LOSC(32768Hz). (+) CMU_LP_LOSC_DISABLE(): Disable low power LOSC(32768Hz). (+) CMU_LP_HRC_ENABLE(): Enable low power HRC(2MHz or 24MHz). (+) CMU_LP_HRC_DISABLE(): Disable low power HRC(2MHz OR 24MHz). (+) CMU_LP_HOSC_ENABLE(): Enable low power HOSC(1MHz -- 24MHz). (+) CMU_LP_HOSC_DISABLE(): Disable low power HOSC(1MHz -- 24MHz). [..] (@) You can refer to the CMU driver header file for used the macros @endverbatim ****************************************************************************** */ #include "ald_cmu.h" /** @addtogroup ES32FXXX_ALD * @{ */ /** @defgroup CMU CMU * @brief CMU module driver * @{ */ /** * @defgroup CMU_Private_Variables CMU Private Variables * @{ */ uint32_t __system_clock = 24000000U; /** * @} */ /** @defgroup CMU_Private_Functions CMU Private Functions * @{ */ /** * @brief Update the current system clock. This function * will be invoked, when system clock has changed. * @param clock: The new clock. * @retval None */ static void cmu_clock_update(uint32_t clock) { __system_clock = clock; if (clock > 1000000) ald_tick_init(TICK_INT_PRIORITY); return; } /** * @brief CMU module interrupt handler * @retval None */ void ald_cmu_irq_handler(void) { /* HOSC stop */ if (READ_BIT(CMU->HOSMCR, CMU_HOSMCR_STPIF_MSK) && READ_BIT(CMU->HOSMCR, CMU_HOSMCR_STPIE_MSK)) { SYSCFG_UNLOCK(); SET_BIT(CMU->HOSMCR, CMU_HOSMCR_STPIF_MSK); SYSCFG_LOCK(); if ((READ_BIT(CMU->HOSMCR, CMU_HOSMCR_CLKS_MSK)) && ((READ_BITS(CMU->CSR, CMU_CSR_SYS_STU_MSK, CMU_CSR_SYS_STU_POSS) == 1) || ((READ_BITS(CMU->CSR, CMU_CSR_SYS_STU_MSK, CMU_CSR_SYS_STU_POSS) == 5)))) cmu_clock_update(READ_BIT(CMU->CFGR, CMU_CFGR_HRCFST_MSK) ? 2000000 : 24000000); ald_cmu_irq_cbk(CMU_HOSC_STOP); } /* HOSC start */ if (READ_BIT(CMU->HOSMCR, CMU_HOSMCR_STRIF_MSK) && READ_BIT(CMU->HOSMCR, CMU_HOSMCR_STRIE_MSK)) { SYSCFG_UNLOCK(); SET_BIT(CMU->HOSMCR, CMU_HOSMCR_STRIF_MSK); SYSCFG_LOCK(); if (!(READ_BIT(CMU->HOSMCR, CMU_HOSMCR_CLKS_MSK)) && ((READ_BITS(CMU->CSR, CMU_CSR_SYS_STU_MSK, CMU_CSR_SYS_STU_POSS) == 5))) cmu_clock_update((READ_BITS(CMU->HOSCCFG, CMU_HOSCCFG_FREQ_MSK, CMU_HOSCCFG_FREQ_POSS) + 1) * 1000000); ald_cmu_irq_cbk(CMU_HOSC_START); } /* LOSC stop */ if (READ_BIT(CMU->LOSMCR, CMU_LOSMCR_STPIF_MSK) && READ_BIT(CMU->LOSMCR, CMU_LOSMCR_STPIE_MSK)) { SYSCFG_UNLOCK(); SET_BIT(CMU->LOSMCR, CMU_LOSMCR_STPIF_MSK); SYSCFG_LOCK(); ald_cmu_irq_cbk(CMU_LOSC_STOP); } /* LOSC start */ if (READ_BIT(CMU->LOSMCR, CMU_LOSMCR_STRIF_MSK) && READ_BIT(CMU->LOSMCR, CMU_LOSMCR_STRIE_MSK)) { SYSCFG_UNLOCK(); SET_BIT(CMU->LOSMCR, CMU_LOSMCR_STRIF_MSK); SYSCFG_LOCK(); ald_cmu_irq_cbk(CMU_LOSC_START); } /* PLL1 lose */ if (READ_BIT(CMU->PULMCR, CMU_PULMCR_ULKIF_MSK) && READ_BIT(CMU->PULMCR, CMU_PULMCR_ULKIE_MSK)) { SYSCFG_UNLOCK(); SET_BIT(CMU->PULMCR, CMU_PULMCR_ULKIF_MSK); SYSCFG_LOCK(); if (READ_BIT(CMU->PULMCR, CMU_PULMCR_CLKS_MSK) && ((READ_BITS(CMU->CSR, CMU_CSR_SYS_STU_MSK, CMU_CSR_SYS_STU_POSS) == 1) || ((READ_BITS(CMU->CSR, CMU_CSR_SYS_STU_MSK, CMU_CSR_SYS_STU_POSS) == 5)))) cmu_clock_update(READ_BIT(CMU->CFGR, CMU_CFGR_HRCFST_MSK) ? 2000000 : 24000000); ald_cmu_irq_cbk(CMU_PLL1_UNLOCK); } return; } /** * @} */ /** @defgroup CMU_Public_Functions CMU Public Functions * @{ */ /** @defgroup CMU_Public_Functions_Group1 System clock configuration * @brief System clock configuration functions * * @verbatim ============================================================================== ##### System clock Configuration functions ##### ============================================================================== [..] This section provides functions allowing to: (+) Configure system clock using default parameters. (+) Configure system clock using specified parameters. (+) Configure PLL1 using specified parameters. (+) Get system clock. @endverbatim * @{ */ /** * @brief Configure system clock using default. * Select CMU_CLOCK_HRC(24MHz) as system clock and * enable CMU_CLOCK_LRC(32768Hz). * @retval The status of ALD. */ ald_status_t ald_cmu_clock_config_default(void) { uint32_t cnt = 4000, tmp; SYSCFG_UNLOCK(); /* Select HRC */ MODIFY_REG(CMU->CSR, CMU_CSR_SYS_CMD_MSK, CMU_CLOCK_HRC << CMU_CSR_SYS_CMD_POSS); while (READ_BIT(CMU->CSR, CMU_CSR_SYS_RDYN_MSK) && (--cnt)); if (READ_BITS(CMU->CSR, CMU_CSR_SYS_STU_MSK, CMU_CSR_SYS_STU_POSS) != CMU_CLOCK_HRC) { SYSCFG_LOCK(); return ERROR; } CLEAR_BIT(CMU->CFGR, CMU_CFGR_HRCFSW_MSK); /* Select 24Mhz */ tmp = READ_REG(CMU->CLKENR); /* Enable HRC/LRC/LOSC */ SET_BIT(tmp, CMU_CLKENR_HRCEN_MSK | CMU_CLKENR_LRCEN_MSK | CMU_CLKENR_LOSCEN_MSK); WRITE_REG(CMU->CLKENR, tmp); SYSCFG_LOCK(); return OK; } /** * @brief Configure system clock using specified parameters * @param clk: The parameter can be one of the following: * @arg @ref CMU_CLOCK_HRC 2MHz or 24MHz * @arg @ref CMU_CLOCK_LRC 32768Hz * @arg @ref CMU_CLOCK_LOSC 32768Hz * @arg @ref CMU_CLOCK_PLL1 32MHz, 48MHz or (32768*1024)Hz * @arg @ref CMU_CLOCK_HOSC 1MHz -- 24MHz * @param clock: The clock which will be set. the value depends * on the parameter of clk. * @retval The status of ALD. */ ald_status_t ald_cmu_clock_config(cmu_clock_t clk, uint32_t clock) { uint32_t cnt = 4000; assert_param(IS_CMU_CLOCK(clk)); SYSCFG_UNLOCK(); switch (clk) { case CMU_CLOCK_HRC: assert_param(clock == 24000000 || clock == 2000000); MODIFY_REG(CMU->CSR, CMU_CSR_SYS_CMD_MSK, CMU_CLOCK_HRC << CMU_CSR_SYS_CMD_POSS); while (READ_BIT(CMU->CSR, CMU_CSR_SYS_RDYN_MSK) && (--cnt)); if (READ_BITS(CMU->CSR, CMU_CSR_SYS_STU_MSK, CMU_CSR_SYS_STU_POSS) != CMU_CLOCK_HRC) { SYSCFG_LOCK(); return ERROR; } if (clock == 24000000) CLEAR_BIT(CMU->CFGR, CMU_CFGR_HRCFSW_MSK); else SET_BIT(CMU->CFGR, CMU_CFGR_HRCFSW_MSK); SET_BIT(CMU->CLKENR, CMU_CLKENR_HRCEN_MSK); for (cnt = 4000; cnt; --cnt); cnt = 4000; while ((!(READ_BIT(CMU->CLKSR, CMU_CLKSR_HRCACT_MSK))) && (--cnt)); cnt = 4000; while ((!(READ_BIT(CMU->CLKSR, CMU_CLKSR_HRCRDY_MSK))) && (--cnt)); cmu_clock_update(clock); break; case CMU_CLOCK_LRC: /* Close SysTick interrupt in lower clock */ SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; MODIFY_REG(CMU->CSR, CMU_CSR_SYS_CMD_MSK, CMU_CLOCK_LRC << CMU_CSR_SYS_CMD_POSS); while (READ_BIT(CMU->CSR, CMU_CSR_SYS_RDYN_MSK) && (--cnt)); if (READ_BITS(CMU->CSR, CMU_CSR_SYS_STU_MSK, CMU_CSR_SYS_STU_POSS) != CMU_CLOCK_LRC) { SYSCFG_LOCK(); return ERROR; } SET_BIT(CMU->CLKENR, CMU_CLKENR_LRCEN_MSK); cnt = 4000; while ((!(READ_BIT(CMU->CLKSR, CMU_CLKSR_LRCACT_MSK))) && (--cnt)); cnt = 4000; while ((!(READ_BIT(CMU->CLKSR, CMU_CLKSR_LRCRDY_MSK))) && (--cnt)); cmu_clock_update(32768); break; case CMU_CLOCK_LOSC: /* Close SysTick interrupt in lower clock */ SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; MODIFY_REG(CMU->CSR, CMU_CSR_SYS_CMD_MSK, CMU_CLOCK_LOSC << CMU_CSR_SYS_CMD_POSS); while (READ_BIT(CMU->CSR, CMU_CSR_SYS_RDYN_MSK) && (--cnt)); if (READ_BITS(CMU->CSR, CMU_CSR_SYS_STU_MSK, CMU_CSR_SYS_STU_POSS) != CMU_CLOCK_LOSC) { SYSCFG_LOCK(); return ERROR; } SET_BIT(CMU->CLKENR, CMU_CLKENR_LOSCEN_MSK); cnt = 4000; while ((!(READ_BIT(CMU->CLKSR, CMU_CLKSR_LOSCACT_MSK))) && (--cnt)); cnt = 4000; while ((!(READ_BIT(CMU->CLKSR, CMU_CLKSR_LOSCRDY_MSK))) && (--cnt)); cmu_clock_update(32768); break; case CMU_CLOCK_PLL1: MODIFY_REG(CMU->CSR, CMU_CSR_SYS_CMD_MSK, CMU_CLOCK_PLL1 << CMU_CSR_SYS_CMD_POSS); while (READ_BIT(CMU->CSR, CMU_CSR_SYS_RDYN_MSK) && (--cnt)); if (READ_BITS(CMU->CSR, CMU_CSR_SYS_STU_MSK, CMU_CSR_SYS_STU_POSS) != CMU_CLOCK_PLL1) { SYSCFG_LOCK(); return ERROR; } SET_BIT(CMU->CLKENR, CMU_CLKENR_PLL1EN_MSK); for (cnt = 4000; cnt; --cnt); cnt = 4000; while ((!(READ_BIT(CMU->CLKSR, CMU_CLKSR_PLL1ACT_MSK))) && (--cnt)); cnt = 4000; while ((!(READ_BIT(CMU->CLKSR, CMU_CLKSR_PLL1RDY_MSK))) && (--cnt)); cmu_clock_update(clock); break; case CMU_CLOCK_HOSC: assert_param(clock <= 24000000); MODIFY_REG(CMU->CSR, CMU_CSR_SYS_CMD_MSK, CMU_CLOCK_HOSC << CMU_CSR_SYS_CMD_POSS); while (READ_BIT(CMU->CSR, CMU_CSR_SYS_RDYN_MSK) && (--cnt)); if (READ_BITS(CMU->CSR, CMU_CSR_SYS_STU_MSK, CMU_CSR_SYS_STU_POSS) != CMU_CLOCK_HOSC) { SYSCFG_LOCK(); return ERROR; } SET_BIT(CMU->CLKENR, CMU_CLKENR_HOSCEN_MSK); MODIFY_REG(CMU->HOSCCFG, CMU_HOSCCFG_FREQ_MSK, clock / 1000000 - 1); for (cnt = 4000; cnt; --cnt); cnt = 4000; while ((!(READ_BIT(CMU->CLKSR, CMU_CLKSR_HOSCACT_MSK))) && (--cnt)); cnt = 4000; while ((!(READ_BIT(CMU->CLKSR, CMU_CLKSR_HOSCRDY_MSK))) && (--cnt)); cmu_clock_update(clock); break; default: break; } SYSCFG_LOCK(); return OK; } /** * @brief Configure PLL1 using specified parameters. * @param input: The input clock type. * @param output: The output clock which can be 32MHz or 48MHz. * When input = CMU_PLL1_INPUT_PLL2; then output must be * CMU_PLL1_OUTPUT_32M, and then the real clock is (32768x1024)Hz. * @retval None */ void ald_cmu_pll1_config(cmu_pll1_input_t input, cmu_pll1_output_t output) { uint32_t cnt = 4000; assert_param(IS_CMU_PLL1_INPUT(input)); assert_param(IS_CMU_PLL1_OUTPUT(output)); SYSCFG_UNLOCK(); if (input == CMU_PLL1_INPUT_HRC_6) { SET_BIT(CMU->CLKENR, CMU_CLKENR_HRCEN_MSK); } else if (input == CMU_PLL1_INPUT_PLL2) { SET_BIT(CMU->CLKENR, CMU_CLKENR_LOSCEN_MSK); CLEAR_BIT(CMU->PLLCFG, CMU_PLLCFG_PLL2RFS_MSK); SET_BIT(CMU->CLKENR, CMU_CLKENR_PLL2EN_MSK); } else { SET_BIT(CMU->CLKENR, CMU_CLKENR_HOSCEN_MSK); } MODIFY_REG(CMU->PLLCFG, CMU_PLLCFG_PLL1RFS_MSK, input << CMU_PLLCFG_PLL1RFS_POSS); MODIFY_REG(CMU->PLLCFG, CMU_PLLCFG_PLL1OS_MSK, output << CMU_PLLCFG_PLL1OS_POS); SET_BIT(CMU->CLKENR, CMU_CLKENR_PLL1EN_MSK); while ((READ_BIT(CMU->PLLCFG, CMU_PLLCFG_PLL1LCKN_MSK)) && (--cnt)); cnt = 4000; while ((!(READ_BIT(CMU->CLKSR, CMU_CLKSR_PLL1RDY_MSK))) && (--cnt)); SYSCFG_LOCK(); return; } /** * @brief Gets MCLK clock. * @retval The value of MCLK clock. */ uint32_t ald_cmu_get_clock(void) { return __system_clock; } /** * @brief Automatic-calibrate internal clock. * @param input: input type: HOSC or LOSC. * @param freq: output frequency: 24MHz or 2MHz. * @retval The result: * - 0 Success * - -1 Failed */ int32_t ald_cmu_auto_calib_clock(cmu_auto_calib_input_t input, cmu_auto_calib_output_t freq) { uint32_t cnt = 5000, tmp; assert_param(IS_CMU_AUTO_CALIB_INPUT(input)); assert_param(IS_CMU_AUTO_CALIB_OUTPUT(freq)); SYSCFG_UNLOCK(); tmp = READ_REG(CMU->HRCACR); MODIFY_REG(tmp, CMU_HRCACR_AC_MSK, 1 << CMU_HRCACR_AC_POSS); MODIFY_REG(tmp, CMU_HRCACR_RFSEL_MSK, input << CMU_HRCACR_RFSEL_POS); MODIFY_REG(tmp, CMU_HRCACR_FREQ_MSK, freq << CMU_HRCACR_FREQ_POS); SET_BIT(tmp, CMU_HRCACR_EN_MSK); WRITE_REG(CMU->HRCACR, tmp); while (cnt--); cnt = 30000; while ((READ_BIT(CMU->HRCACR, CMU_HRCACR_BUSY_MSK)) && (--cnt)); if (READ_BITS(CMU->HRCACR, CMU_HRCACR_STA_MSK, CMU_HRCACR_STA_POSS) != 1) { CLEAR_BIT(CMU->HRCACR, CMU_HRCACR_EN_MSK); SYSCFG_LOCK(); return -1; } SET_BIT(CMU->HRCACR, CMU_HRCACR_WRTRG_MSK); CLEAR_BIT(CMU->HRCACR, CMU_HRCACR_EN_MSK); SYSCFG_LOCK(); return 0; } /** * @} */ /** @defgroup CMU_Public_Functions_Group2 BUS division control * @brief BUS division control functions * * @verbatim ============================================================================== ##### BUS division control functions ##### ============================================================================== [..] This section provides functions allowing to: (+) Configure the bus division. (+) Get AHB1 clock. (+) Get system clock. (+) Get APB1 clock. (+) Get APB2 clock. @endverbatim * @{ */ /** * @brief Configure the bus division. * @param bus: The type of bus: * @arg CMU_HCLK_1 * @arg CMU_SYS * @arg CMU_PCLK_1 * @arg CMU_PCLK_2 * @param div: The value of divider. * @retval None */ void ald_cmu_div_config(cmu_bus_t bus, cmu_div_t div) { assert_param(IS_CMU_BUS(bus)); assert_param(IS_CMU_DIV(div)); SYSCFG_UNLOCK(); switch (bus) { case CMU_HCLK_1: MODIFY_REG(CMU->CFGR, CMU_CFGR_HCLK1DIV_MSK, div << CMU_CFGR_HCLK1DIV_POSS); break; case CMU_SYS: MODIFY_REG(CMU->CFGR, CMU_CFGR_SYSDIV_MSK, div << CMU_CFGR_SYSDIV_POSS); if ((__system_clock >> div) <= 1000000) { /* Close SysTick interrupt in lower clock */ SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; } else { ald_tick_init(TICK_INT_PRIORITY); } break; case CMU_PCLK_1: MODIFY_REG(CMU->CFGR, CMU_CFGR_PCLK1DIV_MSK, div << CMU_CFGR_PCLK1DIV_POSS); break; case CMU_PCLK_2: MODIFY_REG(CMU->CFGR, CMU_CFGR_PCLK2DIV_MSK, div << CMU_CFGR_PCLK2DIV_POSS); break; default: break; } SYSCFG_LOCK(); return; } /** * @brief Get AHB1 clock. * @retval The value of AHB1 clock. */ uint32_t ald_cmu_get_hclk1_clock(void) { uint32_t sys_div = READ_BITS(CMU->CFGR, CMU_CFGR_SYSDIV_MSK, CMU_CFGR_SYSDIV_POSS); uint32_t ahb_div = READ_BITS(CMU->CFGR, CMU_CFGR_HCLK1DIV_MSK, CMU_CFGR_HCLK1DIV_POSS); return (__system_clock >> sys_div) >> ahb_div; } /** * @brief Get system clock * @retval The value of system clock */ uint32_t ald_cmu_get_sys_clock(void) { uint32_t sys_div = READ_BITS(CMU->CFGR, CMU_CFGR_SYSDIV_MSK, CMU_CFGR_SYSDIV_POSS); return __system_clock >> sys_div; } /** * @brief Get APB1 clock. * @retval The value of APB1 clock. */ uint32_t ald_cmu_get_pclk1_clock(void) { uint32_t sys_div = READ_BITS(CMU->CFGR, CMU_CFGR_SYSDIV_MSK, CMU_CFGR_SYSDIV_POSS); uint32_t apb1_div = READ_BITS(CMU->CFGR, CMU_CFGR_PCLK1DIV_MSK, CMU_CFGR_PCLK1DIV_POSS); return (__system_clock >> sys_div) >> apb1_div; } /** * @brief Get APB2 clock. * @retval The value of APB2 clock. */ uint32_t ald_cmu_get_pclk2_clock(void) { uint32_t sys_div = READ_BITS(CMU->CFGR, CMU_CFGR_SYSDIV_MSK, CMU_CFGR_SYSDIV_POSS); uint32_t apb2_div = READ_BITS(CMU->CFGR, CMU_CFGR_PCLK2DIV_MSK, CMU_CFGR_PCLK2DIV_POSS); return (__system_clock >> sys_div) >> apb2_div; } /** * @} */ /** @defgroup CMU_Public_Functions_Group3 Clock safe configure * @brief Clock safe configure functions * * @verbatim ============================================================================== ##### Clock safe configure functions ##### ============================================================================== [..] This section provides functions allowing to: (+) Enable/Disable outer high crystal safe mode. (+) Enable/Disable outer low crystal safe mode. (+) Enable/Disable PLL1 safe mode. (+) Interrupt callback function. @endverbatim * @{ */ /** * @brief Enable/Disable outer high crystal safe mode. * @param clock: the value of outer crystal frequency. * @param status: The new status. * @retval None */ void ald_cmu_hosc_safe_config(cmu_hosc_range_t clock, type_func_t status) { assert_param(IS_CMU_HOSC_RANGE(clock)); assert_param(IS_FUNC_STATE(status)); SYSCFG_UNLOCK(); if (status) { SET_BIT(CMU->HOSMCR, CMU_HOSMCR_STPIF_MSK); MODIFY_REG(CMU->HOSMCR, CMU_HOSMCR_FRQS_MSK, clock << CMU_HOSMCR_FRQS_POSS); SET_BIT(CMU->HOSMCR, CMU_HOSMCR_EN_MSK); SET_BIT(CMU->HOSMCR, CMU_HOSMCR_STPIE_MSK); ald_mcu_irq_config(CMU_IRQn, 3, ENABLE); } else { CLEAR_BIT(CMU->HOSMCR, CMU_HOSMCR_EN_MSK); CLEAR_BIT(CMU->HOSMCR, CMU_HOSMCR_STPIE_MSK); if (READ_BIT(CMU->LOSMCR, CMU_LOSMCR_EN_MSK) == 0 && READ_BIT(CMU->PULMCR, CMU_PULMCR_EN_MSK) == 0) ald_mcu_irq_config(CMU_IRQn, 3, DISABLE); } SYSCFG_LOCK(); return; } /** * @brief Enable/Disable outer low crystal safe mode. * @param status: The new status. * @retval None */ void ald_cmu_losc_safe_config(type_func_t status) { assert_param(IS_FUNC_STATE(status)); SYSCFG_UNLOCK(); if (status) { SET_BIT(CMU->LOSMCR, CMU_LOSMCR_STPIF_MSK); SET_BIT(CMU->LOSMCR, CMU_LOSMCR_EN_MSK); SET_BIT(CMU->LOSMCR, CMU_LOSMCR_STPIE_MSK); ald_mcu_irq_config(CMU_IRQn, 3, ENABLE); } else { CLEAR_BIT(CMU->LOSMCR, CMU_LOSMCR_EN_MSK); CLEAR_BIT(CMU->LOSMCR, CMU_LOSMCR_STPIE_MSK); if (READ_BIT(CMU->HOSMCR, CMU_HOSMCR_EN_MSK) == 0 && READ_BIT(CMU->PULMCR, CMU_PULMCR_EN_MSK) == 0) ald_mcu_irq_config(CMU_IRQn, 3, DISABLE); } SYSCFG_LOCK(); return; } /** * @brief Enable/Disable PLL1 safe mode. * @param status: The new status. * @retval None */ void ald_cmu_pll_safe_config(type_func_t status) { assert_param(IS_FUNC_STATE(status)); SYSCFG_UNLOCK(); if (status) { SET_BIT(CMU->PULMCR, CMU_PULMCR_ULKIF_MSK); MODIFY_REG(CMU->PULMCR, CMU_PULMCR_MODE_MSK, 2 << CMU_PULMCR_MODE_POSS); SET_BIT(CMU->PULMCR, CMU_PULMCR_EN_MSK); SET_BIT(CMU->PULMCR, CMU_PULMCR_ULKIE_MSK); ald_mcu_irq_config(CMU_IRQn, 3, ENABLE); } else { CLEAR_BIT(CMU->PULMCR, CMU_PULMCR_EN_MSK); CLEAR_BIT(CMU->PULMCR, CMU_PULMCR_ULKIE_MSK); if (READ_BIT(CMU->HOSMCR, CMU_HOSMCR_EN_MSK) == 0 && READ_BIT(CMU->LOSMCR, CMU_LOSMCR_EN_MSK) == 0) ald_mcu_irq_config(CMU_IRQn, 3, DISABLE); } SYSCFG_LOCK(); return; } /** * @brief Get current clock source. * @param type: Type of source: HOSC/LOSC/PLL. * @retval Status: * - 0: Current clock is HOSC, LOSC or PLL * - 1: Current clock is HRC, LRC or HRC */ uint32_t ald_cmu_current_clock_source_get(cmu_clock_safe_type_t type) { assert_param(IS_CMU_SAFE_CLOCK_TYPE(type)); if (type == CMU_SAFE_CLK_HOSC) return READ_BITS(CMU->HOSMCR, CMU_HOSMCR_CLKS_MSK, CMU_HOSMCR_CLKS_POS); else if (type == CMU_SAFE_CLK_LOSC) return READ_BITS(CMU->LOSMCR, CMU_LOSMCR_CLKS_MSK, CMU_LOSMCR_CLKS_POS); else return READ_BITS(CMU->PULMCR, CMU_PULMCR_CLKS_MSK, CMU_PULMCR_CLKS_POS); } /** * @brief Get clock state. * @param sr: The state type, see @ref cmu_clock_state_t. * @retval SET/RESET */ flag_status_t ald_cmu_get_clock_state(cmu_clock_state_t sr) { assert_param(IS_CMU_CLOCK_STATE(sr)); if (READ_BIT(CMU->CLKSR, sr)) return SET; return RESET; } /** * @brief Interrupt callback function. * @note This function is declared as __weak to be overwritten in case of other * implementations in user file. * @retval None */ __weak void ald_cmu_irq_cbk(cmu_security_t se) { return; } /** * @} */ /** @defgroup CMU_Public_Functions_Group4 Clock output configure * @brief Clock output configure functions * * @verbatim ============================================================================== ##### Clock output configure functions ##### ============================================================================== [..] This section provides functions allowing to: (+) Configure the high-speed clock output. (+) Configure the low-speed clock output. @endverbatim * @{ */ /** * @brief Configure the high-speed clock output. * @param sel: Select the source: * @arg CMU_OUTPUT_HIGH_SEL_HOSC * @arg CMU_OUTPUT_HIGH_SEL_LOSC * @arg CMU_OUTPUT_HIGH_SEL_HRC * @arg CMU_OUTPUT_HIGH_SEL_LRC * @arg CMU_OUTPUT_HIGH_SEL_HOSM * @arg CMU_OUTPUT_HIGH_SEL_PLL1 * @arg CMU_OUTPUT_HIGH_SEL_PLL2 * @arg CMU_OUTPUT_HIGH_SEL_SYSCLK * @param div: The value of divider: * @arg CMU_OUTPUT_DIV_1 * @arg CMU_OUTPUT_DIV_2 * @arg CMU_OUTPUT_DIV_4 * @arg CMU_OUTPUT_DIV_8 * @arg CMU_OUTPUT_DIV_16 * @arg CMU_OUTPUT_DIV_32 * @arg CMU_OUTPUT_DIV_64 * @arg CMU_OUTPUT_DIV_128 * @param status: The new status. * @retval None */ void ald_cmu_output_high_clock_config(cmu_output_high_sel_t sel, cmu_output_high_div_t div, type_func_t status) { assert_param(IS_CMU_OUTPUT_HIGH_SEL(sel)); assert_param(IS_CMU_OUTPUT_HIGH_DIV(div)); assert_param(IS_FUNC_STATE(status)); SYSCFG_UNLOCK(); if (status) { MODIFY_REG(CMU->CLKOCR, CMU_CLKOCR_HSCOS_MSK, sel << CMU_CLKOCR_HSCOS_POSS); MODIFY_REG(CMU->CLKOCR, CMU_CLKOCR_HSCODIV_MSK, div << CMU_CLKOCR_HSCODIV_POSS); SET_BIT(CMU->CLKOCR, CMU_CLKOCR_HSCOEN_MSK); } else { CLEAR_BIT(CMU->CLKOCR, CMU_CLKOCR_HSCOEN_MSK); } SYSCFG_LOCK(); return; } /** * @brief Configure the low-speed clock output. * @param sel: Select the source: * @arg CMU_OUTPUT_LOW_SEL_LOSC * @arg CMU_OUTPUT_LOW_SEL_LRC * @arg CMU_OUTPUT_LOW_SEL_LOSM * @arg CMU_OUTPUT_LOW_SEL_BUZZ * @arg CMU_OUTPUT_LOW_SEL_ULRC * @param status: The new status. * @retval None */ void ald_cmu_output_low_clock_config(cmu_output_low_sel_t sel, type_func_t status) { assert_param(IS_CMU_OUTPUT_LOW_SEL(sel)); assert_param(IS_FUNC_STATE(status)); SYSCFG_UNLOCK(); if (status) { MODIFY_REG(CMU->CLKOCR, CMU_CLKOCR_LSCOS_MSK, sel << CMU_CLKOCR_LSCOS_POSS); SET_BIT(CMU->CLKOCR, CMU_CLKOCR_LSCOEN_MSK); } else { CLEAR_BIT(CMU->CLKOCR, CMU_CLKOCR_LSCOEN_MSK); } SYSCFG_LOCK(); return; } /** * @} */ /** @defgroup CMU_Public_Functions_Group5 Peripheral Clock configure * @brief Peripheral clock configure functions * * @verbatim ============================================================================== ##### Peripheral clock configure functions ##### ============================================================================== [..] This section provides functions allowing to: (+) Configure buzz clock. (+) Select lptim0 clock source. (+) Select lpuart0 clock source. (+) Select lcd clock source. (+) Enable/Disable peripheral clock. @endverbatim * @{ */ /** * @brief Configure buzz clock. * freq = sysclk / (2^(div + 1) * (dat + 1)) * @param div: The value of divider. * @param dat: The value of coefficient. * @param status: The new status. * @retval None */ void ald_cmu_buzz_config(cmu_buzz_div_t div, uint16_t dat, type_func_t status) { assert_param(IS_CMU_BUZZ_DIV(div)); assert_param(IS_FUNC_STATE(status)); SYSCFG_UNLOCK(); if (status) { MODIFY_REG(CMU->BUZZCR, CMU_BUZZCR_DIV_MSK, div << CMU_BUZZCR_DIV_POSS); MODIFY_REG(CMU->BUZZCR, CMU_BUZZCR_DAT_MSK, dat << CMU_BUZZCR_DAT_POSS); SET_BIT(CMU->BUZZCR, CMU_BUZZCR_EN_MSK); } else { CLEAR_BIT(CMU->BUZZCR, CMU_BUZZCR_EN_MSK); } SYSCFG_LOCK(); return; } /** * @brief Select lptim0 clock source. * @param clock: The clock source: * @arg CMU_LP_PERH_CLOCK_SEL_PCLK2 * @arg CMU_LP_PERH_CLOCK_SEL_PLL1 * @arg CMU_LP_PERH_CLOCK_SEL_PLL2 * @arg CMU_LP_PERH_CLOCK_SEL_HRC * @arg CMU_LP_PERH_CLOCK_SEL_HOSC * @arg CMU_LP_PERH_CLOCK_SEL_LRC * @arg CMU_LP_PERH_CLOCK_SEL_LOSC * @arg CMU_LP_PERH_CLOCK_SEL_ULRC * @arg CMU_LP_PERH_CLOCK_SEL_HRC_1M * @arg CMU_LP_PERH_CLOCK_SEL_HOSC_1M * @arg CMU_LP_PERH_CLOCK_SEL_LOSM * @arg CMU_LP_PERH_CLOCK_SEL_HOSM * @retval None */ void ald_cmu_lptim0_clock_select(cmu_lp_perh_clock_sel_t clock) { assert_param(IS_CMU_LP_PERH_CLOCK_SEL(clock)); SYSCFG_UNLOCK(); MODIFY_REG(CMU->PERICR, CMU_PERICR_LPTIM0_MSK, clock << CMU_PERICR_LPTIM0_POSS); SYSCFG_LOCK(); return; } /** * @brief Select lpuart0 clock source. * @param clock: The clock source: * @arg CMU_LP_PERH_CLOCK_SEL_PCLK2 * @arg CMU_LP_PERH_CLOCK_SEL_PLL1 * @arg CMU_LP_PERH_CLOCK_SEL_PLL2 * @arg CMU_LP_PERH_CLOCK_SEL_HRC * @arg CMU_LP_PERH_CLOCK_SEL_HOSC * @arg CMU_LP_PERH_CLOCK_SEL_LRC * @arg CMU_LP_PERH_CLOCK_SEL_LOSC * @arg CMU_LP_PERH_CLOCK_SEL_ULRC * @arg CMU_LP_PERH_CLOCK_SEL_HRC_1M * @arg CMU_LP_PERH_CLOCK_SEL_HOSC_1M * @arg CMU_LP_PERH_CLOCK_SEL_LOSM * @arg CMU_LP_PERH_CLOCK_SEL_HOSM * @retval None */ void ald_cmu_lpuart0_clock_select(cmu_lp_perh_clock_sel_t clock) { assert_param(IS_CMU_LP_PERH_CLOCK_SEL(clock)); SYSCFG_UNLOCK(); MODIFY_REG(CMU->PERICR, CMU_PERICR_LPUART0_MSK, clock << CMU_PERICR_LPUART0_POSS); SYSCFG_LOCK(); return; } /** * @brief Select lcd clock source. * @param clock: The clock source: * @arg CMU_LCD_SEL_LOSM * @arg CMU_LCD_SEL_LOSC * @arg CMU_LCD_SEL_LRC * @arg CMU_LCD_SEL_ULRC * @arg CMU_LCD_SEL_HRC_1M * @arg CMU_LCD_SEL_HOSC_1M * @retval None */ void ald_cmu_lcd_clock_select(cmu_lcd_clock_sel_t clock) { assert_param(IS_CMU_LCD_CLOCK_SEL(clock)); SYSCFG_UNLOCK(); MODIFY_REG(CMU->PERICR, CMU_PERICR_LCD_MSK, clock << CMU_PERICR_LCD_POSS); SYSCFG_LOCK(); return; } /** * @brief Enable/Disable peripheral clock. * @param perh: The type of peripheral, you can see @ref cmu_perh_t * @param status: The new status. * @retval None */ void ald_cmu_perh_clock_config(cmu_perh_t perh, type_func_t status) { uint32_t idx, pos; assert_param(IS_CMU_PERH(perh)); assert_param(IS_FUNC_STATE(status)); SYSCFG_UNLOCK(); if (perh == CMU_PERH_ALL) { if (status) { WRITE_REG(CMU->AHB1ENR, ~0); WRITE_REG(CMU->APB1ENR, ~0); WRITE_REG(CMU->APB2ENR, ~0); } else { WRITE_REG(CMU->AHB1ENR, 0); WRITE_REG(CMU->APB1ENR, 0); WRITE_REG(CMU->APB2ENR, 0); } SYSCFG_LOCK(); return; } idx = (perh >> 27) & 0x3; pos = perh & ~(0x3 << 27); if (status) { switch (idx) { case 0: SET_BIT(CMU->AHB1ENR, pos); break; case 1: SET_BIT(CMU->APB1ENR, pos); break; case 2: SET_BIT(CMU->APB2ENR, pos); break; default: break; } } else { switch (idx) { case 0: CLEAR_BIT(CMU->AHB1ENR, pos); break; case 1: CLEAR_BIT(CMU->APB1ENR, pos); break; case 2: CLEAR_BIT(CMU->APB2ENR, pos); break; default: break; } } SYSCFG_LOCK(); return; } /** * @} */ /** * @} */ /** * @} */ /** * @} */