880 lines
23 KiB
C
880 lines
23 KiB
C
|
/**
|
||
|
*********************************************************************************
|
||
|
*
|
||
|
* @file ald_cmu.c
|
||
|
* @brief CMU module driver.
|
||
|
*
|
||
|
* @version V1.0
|
||
|
* @date 13 Feb. 2023
|
||
|
* @author AE Team
|
||
|
* @note
|
||
|
* Change Logs:
|
||
|
* Date Author Notes
|
||
|
* 13 Feb. 2023 Lisq The first version
|
||
|
*
|
||
|
* 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.
|
||
|
**********************************************************************************
|
||
|
==============================================================================
|
||
|
##### 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 48MHz.
|
||
|
(+) 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 4MHz or 48MHz
|
||
|
@ref CMU_CLOCK_LRC 32000Hz
|
||
|
@ref CMU_CLOCK_PLL 48MHz, 64MHz or 72MHz
|
||
|
@ref CMU_CLOCK_HOSC 32000Hz, 4MHz, 8MHz, 12MHz, 16MHz, 20MHz, 24MHz
|
||
|
(+) If you select CMU_CLOCK_PLL as system clock, it must config the PLL
|
||
|
using ald_cmu_pll_config() API.
|
||
|
(+) If you get current clock, you can using ald_cmu_get_clock() API.
|
||
|
******************************************************************************
|
||
|
*/
|
||
|
|
||
|
#include "ald_conf.h"
|
||
|
|
||
|
/** @addtogroup ES32VF2264_ALD
|
||
|
* @{
|
||
|
*/
|
||
|
|
||
|
/** @defgroup CMU CMU
|
||
|
* @brief CMU module driver
|
||
|
* @{
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @defgroup CMU_Private_Variables CMU Private Variables
|
||
|
* @{
|
||
|
*/
|
||
|
uint32_t __system_clock = 48000000U;
|
||
|
/**
|
||
|
* @}
|
||
|
*/
|
||
|
|
||
|
/** @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_FLAG_MSK))
|
||
|
&& ((READ_BITS(CMU->CSR, CMU_CSR_SYS_STU_MSK, CMU_CSR_SYS_STU_POSS) == 3)
|
||
|
|| ((READ_BITS(CMU->CSR, CMU_CSR_SYS_STU_MSK, CMU_CSR_SYS_STU_POSS) == 5))))
|
||
|
cmu_clock_update(4000000); /* HRC4M */
|
||
|
|
||
|
ald_cmu_irq_cbk(ALD_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_FLAG_MSK))
|
||
|
&& ((READ_BITS(CMU->CSR, CMU_CSR_SYS_STU_MSK, CMU_CSR_SYS_STU_POSS) == 3)))
|
||
|
{
|
||
|
if(READ_BITS(CMU->HOSCCFG, CMU_HOSCCFG_FREQ_MSK, CMU_HOSCCFG_FREQ_POSS) > 0x5)
|
||
|
cmu_clock_update(4000000); /* HOSC4M */
|
||
|
else
|
||
|
cmu_clock_update((READ_BITS(CMU->HOSCCFG, CMU_HOSCCFG_FREQ_MSK, CMU_HOSCCFG_FREQ_POSS) + 1) * 4000000);
|
||
|
}
|
||
|
|
||
|
ald_cmu_irq_cbk(ALD_CMU_HOSC_START);
|
||
|
}
|
||
|
|
||
|
/* PLL unlock */
|
||
|
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) == 3)
|
||
|
|| ((READ_BITS(CMU->CSR, CMU_CSR_SYS_STU_MSK, CMU_CSR_SYS_STU_POSS) == 5))))
|
||
|
cmu_clock_update(4000000); /* HRC4M */
|
||
|
|
||
|
ald_cmu_irq_cbk(ALD_CMU_PLL_UNLOCK);
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
/**
|
||
|
* @}
|
||
|
*/
|
||
|
|
||
|
/** @defgroup CMU_Public_Functions CMU Public Functions
|
||
|
* @{
|
||
|
*/
|
||
|
|
||
|
/** @defgroup CMU_Public_Functions_Group1 System clock configuration
|
||
|
* @brief System clock configuration functions
|
||
|
*
|
||
|
==============================================================================
|
||
|
##### System clock Configuration functions #####
|
||
|
==============================================================================
|
||
|
[..] This section provides functions allowing to:
|
||
|
(+) Configure system clock using default parameters.
|
||
|
(+) Configure system clock using specified parameters.
|
||
|
(+) Configure PLL using specified parameters.
|
||
|
(+) Get system clock.
|
||
|
* @{
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @brief Configure system clock using default.
|
||
|
* Select CMU_CLOCK_HRC(48MHz) as system clock and
|
||
|
* enable CMU_CLOCK_LRC(32000Hz).
|
||
|
* @retval The status of ALD.
|
||
|
*/
|
||
|
ald_status_t ald_cmu_clock_config_default(void)
|
||
|
{
|
||
|
uint32_t cnt = 4000, tmp;
|
||
|
|
||
|
ald_flash_wait_config(2);
|
||
|
|
||
|
SYSCFG_UNLOCK();
|
||
|
|
||
|
WRITE_REG(CMU->CFGR, 0x0);
|
||
|
|
||
|
tmp = READ_REG(CMU->CLKENR);
|
||
|
/* Enable HRC48M */
|
||
|
SET_BIT(tmp, CMU_CLKENR_HRC48MEN_MSK);
|
||
|
WRITE_REG(CMU->CLKENR, tmp);
|
||
|
|
||
|
for (cnt = 4000; cnt; --cnt);
|
||
|
|
||
|
cnt = 4000;
|
||
|
while ((!(READ_BIT(CMU->CLKSR, CMU_CLKSR_HRC48MACT_MSK))) && (--cnt));
|
||
|
|
||
|
cnt = 4000;
|
||
|
while ((!(READ_BIT(CMU->CLKSR, CMU_CLKSR_HRC48MRDY_MSK))) && (--cnt));
|
||
|
|
||
|
/* Select HRC48M */
|
||
|
MODIFY_REG(CMU->CSR, CMU_CSR_SYS_CMD_MSK, ALD_CMU_CLOCK_HRC48M << CMU_CSR_SYS_CMD_POSS);
|
||
|
|
||
|
cnt = 4000;
|
||
|
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) != ALD_CMU_CLOCK_HRC48M)
|
||
|
{
|
||
|
SYSCFG_LOCK();
|
||
|
return ALD_ERROR;
|
||
|
}
|
||
|
|
||
|
cmu_clock_update(48000000);
|
||
|
|
||
|
SYSCFG_LOCK();
|
||
|
|
||
|
return ALD_OK;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Configure system clock using specified parameters
|
||
|
* @param clk: The parameter can be one of the following:
|
||
|
* @arg @ref CMU_CLOCK_HRC 4MHz or 48MHz
|
||
|
* @arg @ref CMU_CLOCK_LRC 32kHz
|
||
|
* @arg @ref CMU_CLOCK_PLL 48MHz, 64MHz, 72MHz
|
||
|
* @arg @ref CMU_CLOCK_HOSC 4MHz, 8MHz, 12MHz, 16MHz, 20MHz, 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(ald_cmu_clock_t clk, uint32_t clock)
|
||
|
{
|
||
|
uint32_t cnt = 8000;
|
||
|
|
||
|
ald_flash_wait_config(2);
|
||
|
|
||
|
assert_param(IS_CMU_CLOCK(clk));
|
||
|
SYSCFG_UNLOCK();
|
||
|
|
||
|
switch (clk) {
|
||
|
case ALD_CMU_CLOCK_HRC48M:
|
||
|
assert_param(clock == 48000000);
|
||
|
|
||
|
SET_BIT(CMU->CLKENR, CMU_CLKENR_HRC48MEN_MSK);
|
||
|
|
||
|
for (cnt = 4000; cnt; --cnt);
|
||
|
cnt = 4000;
|
||
|
while ((!(READ_BIT(CMU->CLKSR, CMU_CLKSR_HRC48MACT_MSK))) && (--cnt));
|
||
|
cnt = 4000;
|
||
|
while ((!(READ_BIT(CMU->CLKSR, CMU_CLKSR_HRC48MRDY_MSK))) && (--cnt));
|
||
|
|
||
|
MODIFY_REG(CMU->CSR, CMU_CSR_SYS_CMD_MSK, ALD_CMU_CLOCK_HRC48M << CMU_CSR_SYS_CMD_POSS);
|
||
|
|
||
|
cnt = 4000;
|
||
|
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) != ALD_CMU_CLOCK_HRC48M)
|
||
|
{
|
||
|
SYSCFG_LOCK();
|
||
|
return ALD_ERROR;
|
||
|
}
|
||
|
|
||
|
cmu_clock_update(clock);
|
||
|
|
||
|
break;
|
||
|
|
||
|
case ALD_CMU_CLOCK_LRC:
|
||
|
|
||
|
assert_param(clock == 32000);
|
||
|
|
||
|
cnt = 4000;
|
||
|
while ((!(READ_BIT(CMU->CLKSR, CMU_CLKSR_LRCRDY_MSK))) && (--cnt));
|
||
|
|
||
|
MODIFY_REG(CMU->CSR, CMU_CSR_SYS_CMD_MSK, ALD_CMU_CLOCK_LRC << CMU_CSR_SYS_CMD_POSS);
|
||
|
|
||
|
cnt = 4000;
|
||
|
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) != ALD_CMU_CLOCK_LRC)
|
||
|
{
|
||
|
SYSCFG_LOCK();
|
||
|
return ALD_ERROR;
|
||
|
}
|
||
|
|
||
|
cmu_clock_update(clock);
|
||
|
|
||
|
break;
|
||
|
|
||
|
case ALD_CMU_CLOCK_HOSC:
|
||
|
assert_param(clock == 4000000 || clock == 8000000 || clock == 12000000 ||
|
||
|
clock == 16000000 || clock == 20000000 || clock == 24000000);
|
||
|
|
||
|
if(clock > 12000000)
|
||
|
SET_BIT(CMU->CLKENR, CMU_CLKENR_HOSCFLYBPS_MSK); /* HOSC > 12MHz, enable HOSC Bypass Filter */
|
||
|
|
||
|
SET_BIT(CMU->CLKENR, CMU_CLKENR_HOSCEN_MSK);
|
||
|
|
||
|
MODIFY_REG(CMU->HOSCCFG, CMU_HOSCCFG_FREQ_MSK, clock / 4000000 - 1);
|
||
|
|
||
|
for (cnt = 8000; 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));
|
||
|
|
||
|
MODIFY_REG(CMU->CSR, CMU_CSR_SYS_CMD_MSK, ALD_CMU_CLOCK_HOSC << CMU_CSR_SYS_CMD_POSS);
|
||
|
|
||
|
cnt = 4000;
|
||
|
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) != ALD_CMU_CLOCK_HOSC)
|
||
|
{
|
||
|
SYSCFG_LOCK();
|
||
|
return ALD_ERROR;
|
||
|
}
|
||
|
|
||
|
cmu_clock_update(clock);
|
||
|
break;
|
||
|
|
||
|
case ALD_CMU_CLOCK_PLL:
|
||
|
assert_param(clock == 72000000 || clock == 64000000 || clock == 48000000);
|
||
|
|
||
|
SET_BIT(CMU->CLKENR, CMU_CLKENR_PLLEN_MSK);
|
||
|
|
||
|
for (cnt = 4000; cnt; --cnt);
|
||
|
|
||
|
cnt = 4000;
|
||
|
|
||
|
while ((!(READ_BIT(CMU->CLKSR, CMU_CLKSR_PLLACT_MSK))) && (--cnt));
|
||
|
|
||
|
cnt = 4000;
|
||
|
|
||
|
while ((!(READ_BIT(CMU->CLKSR, CMU_CLKSR_PLLRDY_MSK))) && (--cnt));
|
||
|
|
||
|
MODIFY_REG(CMU->CSR, CMU_CSR_SYS_CMD_MSK, ALD_CMU_CLOCK_PLL << CMU_CSR_SYS_CMD_POSS);
|
||
|
|
||
|
cnt = 4000;
|
||
|
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) != ALD_CMU_CLOCK_PLL)
|
||
|
{
|
||
|
SYSCFG_LOCK();
|
||
|
return ALD_ERROR;
|
||
|
}
|
||
|
|
||
|
cmu_clock_update(clock);
|
||
|
|
||
|
break;
|
||
|
|
||
|
case ALD_CMU_CLOCK_HRC4M:
|
||
|
assert_param(clock == 4000000);
|
||
|
|
||
|
SET_BIT(CMU->CLKENR, CMU_CLKENR_HRC4MEN_MSK);
|
||
|
|
||
|
for (cnt = 4000; cnt; --cnt);
|
||
|
|
||
|
cnt = 4000;
|
||
|
|
||
|
while ((!(READ_BIT(CMU->CLKSR, CMU_CLKSR_HRC4MACT_MSK))) && (--cnt));
|
||
|
|
||
|
cnt = 4000;
|
||
|
|
||
|
while ((!(READ_BIT(CMU->CLKSR, CMU_CLKSR_HRC4MRDY_MSK))) && (--cnt));
|
||
|
|
||
|
MODIFY_REG(CMU->CSR, CMU_CSR_SYS_CMD_MSK, ALD_CMU_CLOCK_HRC4M << CMU_CSR_SYS_CMD_POSS);
|
||
|
|
||
|
cnt = 4000;
|
||
|
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) != ALD_CMU_CLOCK_HRC4M)
|
||
|
{
|
||
|
SYSCFG_LOCK();
|
||
|
return ALD_ERROR;
|
||
|
}
|
||
|
|
||
|
cmu_clock_update(clock);
|
||
|
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
SYSCFG_LOCK();
|
||
|
return ALD_OK;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Configure PLL using specified parameters.
|
||
|
* @param input: The input clock type.
|
||
|
* @param output: The output clock which can be 48MHz/64MHz/72MHz.
|
||
|
* @retval None
|
||
|
*/
|
||
|
void ald_cmu_pll_config(ald_cmu_pll_input_t input, ald_cmu_pll_output_t output)
|
||
|
{
|
||
|
uint32_t cnt = 4000;
|
||
|
|
||
|
assert_param(IS_CMU_PLL_INPUT(input));
|
||
|
assert_param(IS_CMU_PLL_OUTPUT(output));
|
||
|
|
||
|
SYSCFG_UNLOCK();
|
||
|
|
||
|
if(READ_BITS(CMU->CSR, CMU_CSR_SYS_STU_MSK, CMU_CSR_SYS_STU_POSS) == ALD_CMU_CLOCK_PLL)
|
||
|
{
|
||
|
SET_BIT(CMU->CLKENR, CMU_CLKENR_HRC48MEN_MSK);
|
||
|
|
||
|
for (cnt = 4000; cnt; --cnt);
|
||
|
|
||
|
cnt = 4000;
|
||
|
while ((!(READ_BIT(CMU->CLKSR, CMU_CLKSR_HRC48MACT_MSK))) && (--cnt));
|
||
|
|
||
|
cnt = 4000;
|
||
|
while ((!(READ_BIT(CMU->CLKSR, CMU_CLKSR_HRC48MRDY_MSK))) && (--cnt));
|
||
|
|
||
|
MODIFY_REG(CMU->CSR, CMU_CSR_SYS_CMD_MSK, ALD_CMU_CLOCK_HRC48M << CMU_CSR_SYS_CMD_POSS);
|
||
|
|
||
|
cnt = 4000;
|
||
|
while (READ_BIT(CMU->CSR, CMU_CSR_SYS_RDYN_MSK) && (--cnt));
|
||
|
}
|
||
|
|
||
|
if (input == ALD_CMU_PLL_INPUT_HRC4M)
|
||
|
{
|
||
|
SET_BIT(CMU->CLKENR, CMU_CLKENR_HRC4MEN_MSK);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SET_BIT(CMU->CLKENR, CMU_CLKENR_HOSCEN_MSK);
|
||
|
|
||
|
if(input == ALD_CMU_PLL_INPUT_HOSC4M)
|
||
|
{
|
||
|
MODIFY_REG(CMU->HOSCCFG, CMU_HOSCCFG_FREQ_MSK, 0);
|
||
|
}
|
||
|
else if(input == ALD_CMU_PLL_INPUT_HOSC8M)
|
||
|
{
|
||
|
MODIFY_REG(CMU->HOSCCFG, CMU_HOSCCFG_FREQ_MSK, 1);
|
||
|
}
|
||
|
else if(input == ALD_CMU_PLL_INPUT_HOSC16M)
|
||
|
{
|
||
|
/* HOSC > 12MHz, enable HOSC Bypass Filter */
|
||
|
SET_BIT(CMU->CLKENR, CMU_CLKENR_HOSCFLYBPS_MSK);
|
||
|
MODIFY_REG(CMU->HOSCCFG, CMU_HOSCCFG_FREQ_MSK, 3);
|
||
|
}
|
||
|
|
||
|
cnt = 20000;
|
||
|
while ((!(READ_BIT(CMU->CLKSR, CMU_CLKSR_HOSCRDY_MSK))) && (--cnt));
|
||
|
}
|
||
|
|
||
|
CLEAR_BIT(CMU->CLKENR, CMU_CLKENR_PLLEN_MSK);
|
||
|
|
||
|
MODIFY_REG(CMU->PLLCFG, CMU_PLLCFG_REFS_MSK, input << CMU_PLLCFG_REFS_POSS);
|
||
|
MODIFY_REG(CMU->PLLCFG, CMU_PLLCFG_CLKOS_MSK, output << CMU_PLLCFG_CLKOS_POSS);
|
||
|
|
||
|
SET_BIT(CMU->PULMCR, CMU_PULMCR_EN_MSK);
|
||
|
MODIFY_REG(CMU->PULMCR, CMU_PULMCR_MODE_MSK, 0x2 << CMU_PULMCR_MODE_POSS);
|
||
|
|
||
|
SYSCFG_LOCK();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Gets current system clock.
|
||
|
* @retval The value of system clock.
|
||
|
*/
|
||
|
uint32_t ald_cmu_get_clock(void)
|
||
|
{
|
||
|
return __system_clock;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @}
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @brief Configure the bus division.
|
||
|
* @param bus: The type of bus:
|
||
|
* @arg CMU_SYS
|
||
|
* @arg CMU_PCLK
|
||
|
* @param div: The value of divider.
|
||
|
* @retval None
|
||
|
*/
|
||
|
void ald_cmu_div_config(ald_cmu_bus_t bus, ald_cmu_div_t div)
|
||
|
{
|
||
|
assert_param(IS_CMU_BUS(bus));
|
||
|
assert_param(IS_CMU_DIV(div));
|
||
|
|
||
|
SYSCFG_UNLOCK();
|
||
|
|
||
|
switch (bus)
|
||
|
{
|
||
|
case ALD_CMU_SYS:
|
||
|
MODIFY_REG(CMU->CFGR, CMU_CFGR_SYSDIV_MSK, div << CMU_CFGR_SYSDIV_POSS);
|
||
|
ald_tick_init(TICK_INT_PRIORITY);
|
||
|
break;
|
||
|
|
||
|
case ALD_CMU_PCLK:
|
||
|
MODIFY_REG(CMU->CFGR, CMU_CFGR_PCLKDIV_MSK, div << CMU_CFGR_PCLKDIV_POSS);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
SYSCFG_LOCK();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Get SYS clock.
|
||
|
* @retval The value of SYS 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 APB clock.
|
||
|
* @retval The value of APB clock.
|
||
|
*/
|
||
|
uint32_t ald_cmu_get_pclk_clock(void)
|
||
|
{
|
||
|
uint32_t sys_div = READ_BITS(CMU->CFGR, CMU_CFGR_SYSDIV_MSK, CMU_CFGR_SYSDIV_POSS);
|
||
|
uint32_t apb_div = READ_BITS(CMU->CFGR, CMU_CFGR_PCLKDIV_MSK, CMU_CFGR_PCLKDIV_POSS);
|
||
|
|
||
|
return (__system_clock >> sys_div) >> apb_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 PLL 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(ald_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->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)
|
||
|
ald_mcu_irq_config(CMU_IRQn, 3, DISABLE);
|
||
|
}
|
||
|
|
||
|
SYSCFG_LOCK();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Get current clock source.
|
||
|
* @retval Status:
|
||
|
* - 0: Current clock is PLL
|
||
|
* - 1: Current clock is HRC
|
||
|
*/
|
||
|
uint32_t ald_cmu_pulmcr_current_clock_source_get(void)
|
||
|
{
|
||
|
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(ald_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(ald_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_HOSM
|
||
|
* @arg CMU_OUTPUT_HIGH_SEL_HRC4M
|
||
|
* @arg CMU_OUTPUT_HIGH_SEL_LRC
|
||
|
* @arg CMU_OUTPUT_HIGH_SEL_SYSCLK
|
||
|
* @arg CMU_OUTPUT_HIGH_SEL_HOSC32K
|
||
|
* @arg CMU_OUTPUT_HIGH_SEL_HRC48M
|
||
|
* @arg CMU_OUTPUT_HIGH_SEL_PLL
|
||
|
* @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(ald_cmu_output_high_sel_t sel,
|
||
|
ald_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_LRC
|
||
|
* @arg CMU_OUTPUT_LOW_SEL_BUZZ
|
||
|
* @param status: The new status.
|
||
|
* @retval None
|
||
|
*/
|
||
|
void ald_cmu_output_low_clock_config(ald_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.
|
||
|
(+) 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(ald_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 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(ald_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 == ALD_CMU_PERH_ALL) {
|
||
|
if (status) {
|
||
|
WRITE_REG(CMU->AHBENR, ~0);
|
||
|
WRITE_REG(CMU->APBENR, ~0);
|
||
|
}
|
||
|
else {
|
||
|
WRITE_REG(CMU->AHBENR, 0);
|
||
|
WRITE_REG(CMU->APBENR, 0);
|
||
|
}
|
||
|
|
||
|
SYSCFG_LOCK();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
idx = ((uint32_t)perh >> 27) & 0x1;
|
||
|
pos = perh & ~(0x1 << 27);
|
||
|
|
||
|
if (status) {
|
||
|
switch (idx) {
|
||
|
case 0:
|
||
|
SET_BIT(CMU->AHBENR, pos);
|
||
|
break;
|
||
|
|
||
|
case 1:
|
||
|
SET_BIT(CMU->APBENR, pos);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
switch (idx) {
|
||
|
case 0:
|
||
|
CLEAR_BIT(CMU->AHBENR, pos);
|
||
|
break;
|
||
|
|
||
|
case 1:
|
||
|
CLEAR_BIT(CMU->APBENR, pos);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
SYSCFG_LOCK();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @}
|
||
|
*/
|
||
|
/**
|
||
|
* @}
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @}
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @}
|
||
|
*/
|