/*! * \file xc_drv_clock.c * * \brief Target xinchip clock driver implementation * * \copyright Revised BSD License, see section \ref LICENSE. * * \code * * _ __ _ ________ _ * | |/ /(_)___ / ____/ /_ (_)___ * | // / __ \/ / / __ \/ / __ \ * / |/ / / / / /___/ / / / / /_/ / * /_/|_/_/_/ /_/\____/_/ /_/_/ .___/ * /_/ * (C) 2022-2025 XinChip * * \endcode * * \author ( XinChip ) Alex-J * * \author ( XinChip ) */ /*----------------------------------------------------------------------------------- INCLUDE HEADE FILES ------------------------------------------------------------------------------------*/ #include "xc_drv_clock.h" /*------------------------------------------------------------------------------------ Local Variables -------------------------------------------------------------------------------------*/ /*------------------------------------------------------------------------------------ Global Variables -------------------------------------------------------------------------------------*/ CLOCK_InitCfg_t clock_cb; /*------------------------------------------------------------------------------------ Func Prototype -------------------------------------------------------------------------------------*/ /*------------------------------------------------------------------------------------ Functions -------------------------------------------------------------------------------------*/ /** **************************************************************************************** * @brief xc_clock_bbpll_common_cfg * @details Common Settings for frequency doubling * @param[in] void * @param[in] void * @param[out] void * @retval void **************************************************************************************** */ void xc_clock_bbpll_common_cfg(void) { cpr_bt_clk_ctl__bt_clk_en__setf(ENABLE); cpr_ctlapbclken_grctl__bt_pclk_en__setf(ENABLE); bt_rf_pm_reg__bt_en_pm__setf(ENABLE); cprao_aon_coreldo_en_set(ENABLE); } /** **************************************************************************************** * @brief xc_clock_bbpll_freq_cfg * @details Initializes the frequency doubling clock * @param[in] hfclk_src :Source clock * @param[in] loopdiv :clock multiplier factor * @param[in] clk_div :Frequency division coefficient * @param[out] void * @retval void **************************************************************************************** */ void xc_clock_bbpll_freq_cfg(CLOCK_HFCLK_Src_Typedef hfclk_src, uint16_t loopdiv, uint8_t clk_div) { if (CLOCK_HFCLK_SRC_RC == hfclk_src) rf_ana27__bbpll_16m_sel__setf(ENABLE); else rf_ana27__bbpll_16m_sel__setf(DISABLE); if(loopdiv != 0x03) rf_ana27__bbpll_core_96m_en__setf(ENABLE); else rf_ana27__bbpll_core_96m_en__setf(DISABLE); rf_ana26__bbpll_loopdiv__setf(loopdiv); rf_ana26__clk_bbpll_en__setf(ENABLE); rf_ana26__clk_bbpll_rstn__setf(ENABLE); rf_ana26__bbpll_en__setf(ENABLE); rf_ana26__bbpll_core_64m_en__setf(ENABLE); cpr_rf_reg4__bbpll_clk_div__setf(clk_div); cpr_rf_reg4__bbpll_clk_en__setf(ENABLE); } /** **************************************************************************************** * @brief xc_clock_set_rc16m * @details The clock is set to RC16M * @param[in] CLOCK_InitCfg_t *cb * @param[in] * @param[out] void * @retval void **************************************************************************************** */ void xc_clock_set_rc16m(CLOCK_InitCfg_t *cb) { cpr_rf_reg3__mclk_src_sel__setf(CLOCK_SRC_RC16M); cb->hfclk_in = CLOCK_HFCLK_IN_16M; cb->systick_unit = SYSTICK_UNIT_IN_16M; } /** **************************************************************************************** * @brief xc_clock_set_rc16m_bbpll_32m * @details RC16M clock overclocked to 32M * @param[in] CLOCK_InitCfg_t *cb * @param[in] * @param[out] void * @retval void **************************************************************************************** */ void xc_clock_set_rc16m_bbpll_32m(CLOCK_InitCfg_t *cb) { xc_clock_bbpll_common_cfg(); xc_clock_bbpll_freq_cfg(cb->hfclk_src, 0x08, 0x01); cpr_rf_reg3__mclk_src_sel__setf(CLOCK_SRC_BBPLL_DIV); cb->hfclk_in = CLOCK_HFCLK_IN_32M; cb->systick_unit = SYSTICK_UNIT_IN_32M; } /** **************************************************************************************** * @brief xc_clock_set_rc16m_bbpll_48m * @details RC16M clock overclocked to 48M * @param[in] CLOCK_InitCfg_t *cb * @param[in] * @param[out] void * @retval void **************************************************************************************** */ void xc_clock_set_rc16m_bbpll_48m(CLOCK_InitCfg_t *cb) { xc_clock_bbpll_common_cfg(); xc_clock_bbpll_freq_cfg(cb->hfclk_src, 0x0C, 0x01); cpr_rf_reg3__mclk_src_sel__setf(CLOCK_SRC_BBPLL_DIV); cb->hfclk_in = CLOCK_HFCLK_IN_48M; cb->systick_unit = SYSTICK_UNIT_IN_48M; } /** **************************************************************************************** * @brief xc_clock_set_rc16m_bbpll_64m * @details RC16M clock overclocked to 64M * @param[in] CLOCK_InitCfg_t *cb * @param[in] * @param[out] void * @retval void **************************************************************************************** */ void xc_clock_set_rc16m_bbpll_64m(CLOCK_InitCfg_t *cb) { xc_clock_bbpll_common_cfg(); xc_clock_bbpll_freq_cfg(cb->hfclk_src, 0x08, 0x01); cpr_rf_reg3__mclk_src_sel__setf(CLOCK_SRC_BBPLL); cb->hfclk_in = CLOCK_HFCLK_IN_64M; cb->systick_unit = SYSTICK_UNIT_IN_64M; } /** **************************************************************************************** * @brief xc_clock_set_rc16m_bbpll_96m * @details RC16M clock overclocked to 96M * @param[in] CLOCK_InitCfg_t *cb * @param[in] * @param[out] void * @retval void **************************************************************************************** */ void xc_clock_set_rc16m_bbpll_96m(CLOCK_InitCfg_t *cb) { xc_clock_bbpll_common_cfg(); xc_clock_bbpll_freq_cfg(cb->hfclk_src, 0x0C, 0x01); cpr_rf_reg3__mclk_src_sel__setf(CLOCK_SRC_BBPLL); cb->hfclk_in = CLOCK_HFCLK_IN_96M; cb->systick_unit = SYSTICK_UNIT_IN_96M; } /** **************************************************************************************** * @brief xc_clock_set_osc32m_bbpll_16m * @details osc32M Clock overclocked to 16M * @param[in] CLOCK_InitCfg_t *cb * @param[in] * @param[out] void * @retval void **************************************************************************************** */ void xc_clock_set_osc32m_bbpll_16m(CLOCK_InitCfg_t *cb) { xc_clock_bbpll_common_cfg(); xc_clock_bbpll_freq_cfg(cb->hfclk_src, 0x06, 0x05); cpr_rf_reg3__mclk_src_sel__setf(CLOCK_SRC_BBPLL_DIV); cb->hfclk_in = CLOCK_HFCLK_IN_16M; cb->systick_unit = SYSTICK_UNIT_IN_16M; } /** **************************************************************************************** * @brief xc_clock_set_osc32m_div_16m * @details osc32M Clock divided into 16M * @param[in] CLOCK_InitCfg_t *cb * @param[in] * @param[out] void * @retval void **************************************************************************************** */ void xc_clock_set_osc32m_div_16m(CLOCK_InitCfg_t *cb) { //M0_FCLK cpr_m0_fclk_ctl__m0_fclk_div_p__setf(0x1); cpr_m0_fclk_ctl__m0_fclk_direct_sw__setf(0x1); //CTL_PCLK cpr_ctl_pclk_grctl__ctl_pclk_gr__setf(0x8); cpr_ctl_pclk_grctl__ctl_pclk_gr_upd__setf(0x1); cprao_aon_bbldo_adj_set(0x3c); /* The value needs to be configured to 7, otherwise the current drop will be slower during sleep and the clock accuracy of the rc32k will be affected. */ cprao_aon_lpoldo_adj_set(0x7); cb->hfclk_in = CLOCK_HFCLK_IN_16M; cb->systick_unit = SYSTICK_UNIT_IN_16M; } /** **************************************************************************************** * @brief xc_clock_set_osc32m * @details The clock is set to osc32M * @param[in] CLOCK_InitCfg_t *cb * @param[in] * @param[out] void * @retval void **************************************************************************************** */ void xc_clock_set_osc32m(CLOCK_InitCfg_t *cb) { cpr_rf_reg3__mclk_src_sel__setf(CLOCK_SRC_OSC32M); cb->hfclk_in = CLOCK_HFCLK_IN_32M; cb->systick_unit = SYSTICK_UNIT_IN_32M; } #if (CONFIG_HFCLK_IS_OSC32M_PLL_32M) /** **************************************************************************************** * @brief xc_clock_set_osc32m_bbpll_32m * @details osc32M Clock overclocked to 64M and hflck is 32M * @param[in] CLOCK_InitCfg_t *cb * @param[in] * @param[out] void * @retval void **************************************************************************************** */ void xc_clock_set_osc32m_bbpll_32m(CLOCK_InitCfg_t *cb) { xc_clock_bbpll_common_cfg(); xc_clock_bbpll_freq_cfg(cb->hfclk_src, 0x04, 0x01); cpr_rf_reg3__mclk_src_sel__setf(CLOCK_SRC_BBPLL_DIV); cb->hfclk_in = CLOCK_HFCLK_IN_32M; cb->systick_unit = SYSTICK_UNIT_IN_32M; } #endif /** **************************************************************************************** * @brief xc_clock_set_osc32m_bbpll_48m * @details osc32M Clock overclocked to 48M * @param[in] CLOCK_InitCfg_t *cb * @param[in] * @param[out] void * @retval void **************************************************************************************** */ void xc_clock_set_osc32m_bbpll_48m(CLOCK_InitCfg_t *cb) { xc_clock_bbpll_common_cfg(); xc_clock_bbpll_freq_cfg(cb->hfclk_src, 0x03, 0x01); cpr_rf_reg3__mclk_src_sel__setf(CLOCK_SRC_BBPLL_DIV); cb->hfclk_in = CLOCK_HFCLK_IN_48M; cb->systick_unit = SYSTICK_UNIT_IN_48M; } /** **************************************************************************************** * @brief xc_clock_set_osc32m_bbpll_64m * @details osc32M Clock overclocked to 64M * @param[in] CLOCK_InitCfg_t *cb * @param[in] * @param[out] void * @retval void **************************************************************************************** */ void xc_clock_set_osc32m_bbpll_64m(CLOCK_InitCfg_t *cb) { xc_clock_bbpll_common_cfg(); xc_clock_bbpll_freq_cfg(cb->hfclk_src, 0x04, 0x01); cpr_rf_reg3__mclk_src_sel__setf(CLOCK_SRC_BBPLL); cb->hfclk_in = CLOCK_HFCLK_IN_64M; cb->systick_unit = SYSTICK_UNIT_IN_64M; } /** **************************************************************************************** * @brief xc_clock_set_osc32m_bbpll_96m * @details osc32M Clock overclocked to 96M * @param[in] CLOCK_InitCfg_t *cb * @param[in] * @param[out] void * @retval void **************************************************************************************** */ void xc_clock_set_osc32m_bbpll_96m(CLOCK_InitCfg_t *cb) { xc_clock_bbpll_common_cfg(); xc_clock_bbpll_freq_cfg(cb->hfclk_src, 0x03, 0x01); cpr_rf_reg3__mclk_src_sel__setf(CLOCK_SRC_BBPLL); cb->hfclk_in = CLOCK_HFCLK_IN_96M; cb->systick_unit = SYSTICK_UNIT_IN_96M; } /** **************************************************************************************** * @brief xc_clock_hfclk_set * @details High speed clock setting * @param[in] CLOCK_HFCLK_Src_Typedef hfclk_src * @param[in] CLOCK_HFCLK_In_Typedef hfclk_in * @param[out] void * @retval void **************************************************************************************** */ void xc_clock_hfclk_set(CLOCK_HFCLK_Src_Typedef hfclk_src, CLOCK_HFCLK_In_Typedef hfclk_in) { uint32_t baudrate, uart_clk, div, mul, clk_ctl, adj_div, m0_fclk_div; CLOCK_InitCfg_t *pclock_cb = &clock_cb; pclock_cb->hfclk_src = hfclk_src; switch (hfclk_src) { case CLOCK_HFCLK_SRC_RC: { if (CLOCK_HFCLK_IN_16M == hfclk_in) { xc_clock_set_rc16m(pclock_cb); } else if (CLOCK_HFCLK_IN_32M == hfclk_in) { xc_clock_set_rc16m_bbpll_32m(pclock_cb); } else if (CLOCK_HFCLK_IN_48M == hfclk_in) { xc_clock_set_rc16m_bbpll_48m(pclock_cb); } else if (CLOCK_HFCLK_IN_64M == hfclk_in) { xc_clock_set_rc16m_bbpll_64m(pclock_cb); } else if (CLOCK_HFCLK_IN_96M == hfclk_in) { xc_clock_set_rc16m_bbpll_96m(pclock_cb); } } break; case CLOCK_HFCLK_SRC_XTAL: { // if(cpr_m0_fclk_ctl__m0_fclk_div__getf( )) { // cpr_m0_fclk_ctl__m0_fclk_div_p__setf(0); // cpr_m0_fclk_ctl__m0_fclk_direct_sw__setf(0x1); // } if (CLOCK_HFCLK_IN_16M == hfclk_in) { xc_clock_set_osc32m_div_16m(pclock_cb); } else if (CLOCK_HFCLK_IN_32M == hfclk_in) { #if (CONFIG_HFCLK_IS_OSC32M_PLL_32M) xc_clock_set_osc32m_bbpll_32m(pclock_cb); #else xc_clock_set_osc32m(pclock_cb); #endif } else if (CLOCK_HFCLK_IN_48M == hfclk_in) { xc_clock_set_osc32m_bbpll_48m(pclock_cb); } else if (CLOCK_HFCLK_IN_64M == hfclk_in) { xc_clock_set_osc32m_bbpll_64m(pclock_cb); } else if (CLOCK_HFCLK_IN_96M == hfclk_in) { xc_clock_set_osc32m_bbpll_96m(pclock_cb); } } break; } m0_fclk_div = cpr_m0_fclk_ctl__m0_fclk_div__getf( ); uart_clk = xc_clock_hfclk_in_get() * (m0_fclk_div+1); baudrate = cpr_uart0_clk_ctl_get(); mul = (baudrate >> 16) & 0xFFFF; div = (baudrate & 0xFFFF); adj_div = uart_clk / 1000000; clk_ctl = (mul << 16) | (div * adj_div / 32); cpr_uart0_clk_ctl_set(clk_ctl); } /** **************************************************************************************** * @brief xc_clock_lfclk_set * @details Low speed clock setting * @param[in] CLOCK_LFCLK_Src_Typedef lfclk_src * @param[in] CLOCK_LFCLK_In_Typedef lfclk_in * @param[out] void * @retval void **************************************************************************************** */ void xc_clock_lfclk_set(CLOCK_LFCLK_Src_Typedef lfclk_src, CLOCK_LFCLK_In_Typedef lfclk_in) { clock_cb.lfclk_src = lfclk_src; clock_cb.lfclk_in = lfclk_in; if(lfclk_src == CLOCK_LFCLK_SRC_XTAL) { GPIO_InitCfg_t gpio_cfg = {0}; gpio_cfg.Mux = GPIO_Mux0; gpio_cfg.FunSel = GPIO_Dx; gpio_cfg.Dir = GPIO_DIR_INPUT; gpio_cfg.Pull = GPIO_NOPULL; gpio_cfg.Int = NOT_INT; gpio_cfg.Pin = 20; xc_gpio_init(&gpio_cfg); gpio_cfg.Pin = 21; xc_gpio_init(&gpio_cfg); cprao_aon_xtl32k_val__xtl32k_v__setf(0x01); cprao_aon_xtl32k_val__xtl32k_en__setf(ENABLE); cprao_aon_ctl_clk32k__osc32k_sel__setf(2); } else if(lfclk_src == CLOCK_LFCLK_SRC_RC) { } } /** **************************************************************************************** * @brief xc_clock_init_cfg * @details Configure the clock initially * @param[in] CLOCK_InitCfg_t *clock_cfg * @param[out] void * @retval void **************************************************************************************** */ void xc_clock_init_cfg(CLOCK_InitCfg_t *clock_cfg) { xc_clock_hfclk_set(clock_cfg->hfclk_src, clock_cfg->hfclk_in); xc_clock_lfclk_set(clock_cfg->lfclk_src, clock_cfg->lfclk_in); xc_pwr_vol_set(); } /** **************************************************************************************** * @brief xc_clock_hfclk_in_get * @details Gets the current high speed clock ( system clock ) * @param[in] * @param[out] void * @retval clock_cb.hfclk_in **************************************************************************************** */ CLOCK_HFCLK_In_Typedef xc_clock_hfclk_in_get(void) { return clock_cb.hfclk_in; } /** **************************************************************************************** * @brief xc_clock_lfclk_in_get * @details Gets the current low speed clock ( Low power clock ) * @param[in] * @param[out] void * @retval clock_cb.lfclk_in **************************************************************************************** */ CLOCK_LFCLK_In_Typedef xc_clock_lfclk_in_get(void) { return clock_cb.lfclk_in; } /** **************************************************************************************** * @brief xc_clock_hfclk_src_get * @details Obtain the current high-speed source clock * @param[in] * @param[out] void * @retval clock_cb.hfclk_src **************************************************************************************** */ CLOCK_HFCLK_Src_Typedef xc_clock_hfclk_src_get(void) { return clock_cb.hfclk_src; } /** **************************************************************************************** * @brief xc_clock_lfclk_src_get * @details Obtain the current low-speed source clock * @param[in] * @param[out] void * @retval clock_cb.lfclk_src **************************************************************************************** */ CLOCK_LFCLK_Src_Typedef xc_clock_lfclk_src_get(void) { return clock_cb.lfclk_src; } /** **************************************************************************************** * @brief xc_systick_unit_get * @details Obtain the current systick unit * @param[in] * @param[out] void * @retval clock_cb.lfclk_src **************************************************************************************** */ Systick_Unit_Typedef xc_systick_unit_get(void) { return clock_cb.systick_unit; }