ChibiOS/os/hal/ports/STM32/STM32G4xx/hal_lld.c

718 lines
21 KiB
C

/*
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
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
http://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.
*/
/**
* @file STM32G4xx/hal_lld.c
* @brief STM32G4xx HAL subsystem low level driver source.
*
* @addtogroup HAL
* @{
*/
#include "hal.h"
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/**
* @brief CMSIS system core clock variable.
* @note It is declared in system_stm32g4xx.h.
*/
uint32_t SystemCoreClock = STM32_HCLK;
#if defined(HAL_LLD_USE_CLOCK_MANAGEMENT) || defined(__DOXYGEN__)
/**
* @brief Post-reset clock configuration.
*/
const halclkcfg_t hal_clkcfg_reset = {
.pwr_cr1 = PWR_CR1_VOS_0,
.pwr_cr2 = 0U,
.pwr_cr3 = PWR_CR3_EIWF,
.pwr_cr4 = 0U,
.pwr_cr5 = PWR_CR5_R1MODE,
.rcc_cr = RCC_CR_HSIKERON | RCC_CR_HSION,
.rcc_cfgr = RCC_CFGR_SW_HSI,
.rcc_pllcfgr = 0U,
.flash_acr = FLASH_ACR_DBG_SWEN | FLASH_ACR_DCEN |
FLASH_ACR_ICEN | FLASH_ACR_LATENCY_1WS
};
/**
* @brief Default clock configuration.
*/
const halclkcfg_t hal_clkcfg_default = {
.pwr_cr1 = STM32_VOS_RANGE1,
.pwr_cr2 = STM32_PWR_CR2,
.pwr_cr3 = STM32_PWR_CR3,
.pwr_cr4 = STM32_PWR_CR4,
.pwr_cr5 = STM32_CR5BITS,
.rcc_cr = 0U
#if STM32_HSI16_ENABLED
| RCC_CR_HSIKERON | RCC_CR_HSION
#endif
#if STM32_HSE_ENABLED
| RCC_CR_HSEON
#endif
#if STM32_ACTIVATE_PLL
| RCC_CR_PLLON
#endif
,
.rcc_cfgr = STM32_MCOPRE | STM32_MCOSEL |
STM32_PPRE2 | STM32_PPRE1 |
STM32_HPRE | STM32_SW,
.rcc_pllcfgr = STM32_PLLPDIV | STM32_PLLR |
STM32_PLLREN | STM32_PLLQ |
STM32_PLLQEN | STM32_PLLP |
STM32_PLLPEN | STM32_PLLN |
STM32_PLLM | STM32_PLLSRC,
.flash_acr = FLASH_ACR_DBG_SWEN | FLASH_ACR_DCEN |
FLASH_ACR_ICEN | FLASH_ACR_PRFTEN |
STM32_FLASHBITS
};
#endif /* defined(HAL_LLD_USE_CLOCK_MANAGEMENT) */
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
#if defined(HAL_LLD_USE_CLOCK_MANAGEMENT) || defined(__DOXYGEN__)
/**
* @brief Dynamic clock points for this device.
*/
static halfreq_t clock_points[CLK_ARRAY_SIZE];
/**
* @brief Type of a structure representing system limits.
*/
typedef struct {
halfreq_t sysclk_max_boost;
halfreq_t sysclk_max_noboost;
halfreq_t pllin_max;
halfreq_t pllin_min;
halfreq_t pllvco_max;
halfreq_t pllvco_min;
halfreq_t pllp_max;
halfreq_t pllp_min;
halfreq_t pllq_max;
halfreq_t pllq_min;
halfreq_t pllr_max;
halfreq_t pllr_min;
halfreq_t flash_thresholds[9];
} system_limits_t;
/**
* @brief System limits for VOS RANGE1.
*/
static const system_limits_t vos_range1 = {
.sysclk_max_boost = 170000000U,
.sysclk_max_noboost = 150000000U,
.pllin_max = 16000000U,
.pllin_min = 2660000U,
.pllvco_max = 344000000U,
.pllvco_min = 96000000U,
.pllp_max = 170000000U,
.pllp_min = 2064500U,
.pllq_max = 170000000U,
.pllq_min = 8000000U,
.pllr_max = 170000000U,
.pllr_min = 8000000U,
.flash_thresholds = { 20000000U, 40000000U, 60000000U, 80000000U,
100000000U, 120000000U, 140000000U, 160000000U,
170000000U}
};
/**
* @brief System limits for VOS RANGE2.
*/
static const system_limits_t vos_range2 = {
.sysclk_max_boost = 0U,
.sysclk_max_noboost = 26000000U,
.pllin_max = 16000000U,
.pllin_min = 2660000U,
.pllvco_max = 128000000U,
.pllvco_min = 96000000U,
.pllp_max = 26000000U,
.pllp_min = 2064500U,
.pllq_max = 26000000U,
.pllq_min = 8000000U,
.pllr_max = 26000000U,
.pllr_min = 8000000U,
.flash_thresholds = { 8000000U, 16000000U, 26000000U, 0U,
0U, 0U, 0U, 0U,
0U}
};
#endif /* defined(HAL_LLD_USE_CLOCK_MANAGEMENT) */
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/**
* @brief Resets the backup domain.
*/
__STATIC_INLINE void bd_reset(void) {
/* Reset BKP domain if different clock source selected.*/
if ((RCC->BDCR & STM32_RTCSEL_MASK) != STM32_RTCSEL) {
/* Backup domain reset.*/
RCC->BDCR = RCC_BDCR_BDRST;
RCC->BDCR = 0U;
}
}
/**
* @brief Initializes the backup domain.
* @note WARNING! Changing RTC clock source impossible without reset
* of the whole BKP domain.
*/
__STATIC_INLINE void bd_init(void) {
uint32_t bdcr;
/* Current settings.*/
bdcr = RCC->BDCR;
#if HAL_USE_RTC
/* RTC clock enabled.*/
if ((bdcr & RCC_BDCR_RTCEN) == 0) {
bdcr |= RCC_BDCR_RTCEN;
}
#endif /* HAL_USE_RTC */
/* Selectors.*/
bdcr &= ~(STM32_RTCSEL_MASK | STM32_LSCOSEL_MASK);
bdcr |= STM32_RTCSEL | STM32_LSCOSEL;
/* Final settings.*/
RCC->BDCR = bdcr;
}
#if defined(HAL_LLD_USE_CLOCK_MANAGEMENT) || defined(__DOXYGEN__)
/**
* @brief Recalculates the clock tree frequencies.
*
* @param[in] ccp pointer to clock a @p halclkcfg_t structure
* @return The frequency calculation result.
* @retval false if the clock settings look valid
* @retval true if the clock settings look invalid
*
* @notapi
*/
static bool hal_lld_clock_check_tree(const halclkcfg_t *ccp) {
static const uint32_t hprediv[16] = {1U, 1U, 1U, 1U, 1U, 1U, 1U, 1U,
2U, 4U, 8U, 16U, 64U, 128U, 256U, 512U};
static const uint32_t pprediv[16] = {1U, 1U, 1U, 1U, 2U, 4U, 8U, 16U};
const system_limits_t *slp;
halfreq_t hsi16clk = 0U, hseclk = 0U, pllselclk;
halfreq_t pllpclk = 0U, pllqclk = 0U, pllrclk = 0U;
halfreq_t sysclk, hclk, pclk1, pclk2, pclk1tim, pclk2tim, mcoclk;
uint32_t mcodiv;
/* System limits based on desired VOS settings.*/
if ((ccp->pwr_cr1 & PWR_CR1_VOS_Msk) == PWR_CR1_VOS_1) {
slp = &vos_range2;
}
else if ((ccp->pwr_cr1 & PWR_CR1_VOS_Msk) == PWR_CR1_VOS_0) {
slp = &vos_range1;
}
else {
return true;
}
/* HSI16 clock.*/
if ((ccp->rcc_cr & RCC_CR_HSION) != 0U) {
hsi16clk = STM32_HSI16CLK;
}
/* HSE clock.*/
if ((ccp->rcc_cr & RCC_CR_HSEON) != 0U) {
hseclk = STM32_HSECLK;
}
/* PLL MUX clock.*/
switch (ccp->rcc_pllcfgr & RCC_PLLCFGR_PLLSRC_Msk) {
case RCC_PLLCFGR_PLLSRC_HSI:
pllselclk = hsi16clk;
break;
case RCC_PLLCFGR_PLLSRC_HSE:
pllselclk = hseclk;
break;
default:
pllselclk = 0U;
}
/* PLL outputs.*/
if ((ccp->rcc_cr & RCC_CR_PLLON) != 0U) {
uint32_t pllmdiv, pllndiv, pllpdiv, pllqdiv, pllrdiv;
halfreq_t pllvcoclk;
/* PLL M divider.*/
pllmdiv = ((ccp->rcc_pllcfgr & RCC_PLLCFGR_PLLM_Msk) >> RCC_PLLCFGR_PLLM_Pos) + 1U;
/* PLL N divider.*/
pllndiv = (ccp->rcc_pllcfgr & RCC_PLLCFGR_PLLN_Msk) >> RCC_PLLCFGR_PLLN_Pos;
if (pllndiv < 8) {
return true;
}
/* PLL VCO frequency.*/
pllvcoclk = (pllselclk / (halfreq_t)pllmdiv) * (halfreq_t)pllndiv;
if((pllvcoclk < slp->pllvco_min) || (pllvcoclk > slp->pllvco_max)) {
return true;
}
/* PLL P output frequency.*/
pllpdiv = (ccp->rcc_pllcfgr & RCC_PLLCFGR_PLLPDIV_Msk) >> RCC_PLLCFGR_PLLPDIV_Pos;
if (pllpdiv == 1U) {
return true;
}
if (pllpdiv == 0U) {
if ((ccp->rcc_pllcfgr & RCC_PLLCFGR_PLLP) == 0U) {
pllpdiv = 7U;
}
else {
pllpdiv = 17U;
}
}
if ((ccp->rcc_pllcfgr & RCC_PLLCFGR_PLLPEN) != 0U) {
pllpclk = pllvcoclk / pllpdiv;
if((pllpclk < slp->pllp_min) || (pllpclk > slp->pllp_max)) {
return true;
}
}
/* PLL Q output frequency.*/
pllqdiv = 2U + (2U * (ccp->rcc_pllcfgr & RCC_PLLCFGR_PLLQ_Msk) >> RCC_PLLCFGR_PLLQ_Pos);
if ((ccp->rcc_pllcfgr & RCC_PLLCFGR_PLLQEN) != 0U) {
pllqclk = pllvcoclk / pllqdiv;
if((pllqclk < slp->pllq_min) || (pllqclk > slp->pllq_max)) {
return true;
}
}
/* PLL R output frequency.*/
pllrdiv = 2U + (2U * (ccp->rcc_pllcfgr & RCC_PLLCFGR_PLLR_Msk) >> RCC_PLLCFGR_PLLR_Pos);
if ((ccp->rcc_pllcfgr & RCC_PLLCFGR_PLLREN) != 0U) {
pllrclk = pllvcoclk / pllrdiv;
if((pllrclk < slp->pllr_min) || (pllrclk > slp->pllr_max)) {
return true;
}
}
}
/* SYSCLK frequency.*/
switch(ccp->rcc_cfgr & RCC_CFGR_SW_Msk) {
case RCC_CFGR_SW_HSI:
sysclk = hsi16clk;
break;
case RCC_CFGR_SW_HSE:
sysclk = hseclk;
break;
case RCC_CFGR_SW_PLL:
sysclk = pllrclk;
break;
default:
sysclk = 0U;
}
if ((ccp->pwr_cr5 & PWR_CR5_R1MODE) == 0U) {
if (sysclk < slp->sysclk_max_boost) {
return true;
}
}
else {
if (sysclk < slp->sysclk_max_noboost) {
return true;
}
}
/* HCLK frequency.*/
hclk = sysclk / hprediv[(ccp->rcc_cfgr & RCC_CFGR_HPRE_Msk) >> RCC_CFGR_HPRE_Pos];
/* PPRE1 frequency.*/
pclk1 = hclk / pprediv[(ccp->rcc_cfgr & RCC_CFGR_PPRE1_Msk) >> RCC_CFGR_PPRE1_Pos];
if ((ccp->rcc_cfgr & RCC_CFGR_PPRE1_Msk) < RCC_CFGR_PPRE1_DIV2) {
pclk1tim = pclk1;
}
else {
pclk1tim = pclk1 * 2U;
}
/* PPRE2 frequency.*/
pclk2 = hclk / pprediv[(ccp->rcc_cfgr & RCC_CFGR_PPRE2_Msk) >> RCC_CFGR_PPRE2_Pos];
if ((ccp->rcc_cfgr & RCC_CFGR_PPRE1_Msk) < RCC_CFGR_PPRE2_DIV2) {
pclk2tim = pclk2;
}
else {
pclk2tim = pclk2 * 2U;
}
/* MCO clock.*/
switch(ccp->rcc_cfgr & RCC_CFGR_MCOSEL_Msk) {
case STM32_MCOSEL_NOCLOCK:
mcoclk = 0U;
break;
case STM32_MCOSEL_SYSCLK:
mcoclk = sysclk;
break;
case STM32_MCOSEL_HSI16:
mcoclk = hsi16clk;
break;
case STM32_MCOSEL_HSE:
mcoclk = hseclk;
break;
case STM32_MCOSEL_PLLRCLK:
mcoclk = pllrclk;
break;
case STM32_MCOSEL_LSI:
mcoclk = STM32_LSICLK;
break;
case STM32_MCOSEL_LSE:
mcoclk = STM32_LSECLK;
break;
case STM32_MCOSEL_HSI48:
mcoclk = STM32_HSI48CLK;
break;
default:
mcoclk = 0U;
}
mcodiv = 1U << ((ccp->rcc_cfgr & RCC_CFGR_MCOPRE_Msk) >> RCC_CFGR_MCOPRE_Pos);
if (mcodiv > 16U) {
return true;
}
mcoclk /= mcodiv;
/* Writing out results.*/
clock_points[CLK_SYSCLK] = sysclk;
clock_points[CLK_PLLPCLK] = pllpclk;
clock_points[CLK_PLLQCLK] = pllqclk;
clock_points[CLK_PLLRCLK] = pllrclk;
clock_points[CLK_HCLK] = hclk;
clock_points[CLK_PCLK1] = pclk1;
clock_points[CLK_PCLK1TIM] = pclk1tim;
clock_points[CLK_PCLK2] = pclk2;
clock_points[CLK_PCLK2TIM] = pclk2tim;
clock_points[CLK_MCO] = mcoclk;
return false;
}
/**
* @brief Switches to a different clock configuration.
*
* @param[in] ccp pointer to clock a @p halclkcfg_t structure
* @return The clock switch result.
* @retval false if the clock switch succeeded
* @retval true if the clock switch failed
*
* @notapi
*/
bool hal_lld_clock_raw_switch(const halclkcfg_t *ccp) {
/* Restoring default PWR settings related clocks and sleep modes.*/
PWR->CR1 = PWR_CR1_VOS_0;
PWR->CR2 = 0U;
PWR->CR3 = PWR_CR3_EIWF;
PWR->CR4 = 0U;
/* Waiting for all regulator status bits to be cleared, this means that
power levels are stable.*/
while ((PWR->SR2 & (PWR_SR2_VOSF | PWR_SR2_REGLPF)) != 0U) {
/* Waiting for the regulator to be ready.*/
}
/* Making sure HSI16 is activated.*/
hsi16_enable();
/* Disabling boost mode.*/
PWR->CR5 = PWR_CR5_R1MODE;
/* Switching to the HSI oscillator.*/
RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_SW_Msk) | RCC_CFGR_SW_HSI;
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI) {
/* Waiting for clock switch.*/
}
/* Resetting flash ACR settings to the default value.*/
FLASH->ACR = 0x00040601U;
/* HSE setup, if required, before starting the PLL.*/
if ((ccp->rcc_cr & RCC_CR_HSEON) != 0U) {
hse_enable();
}
/* PLL setup.*/
RCC->PLLCFGR = ccp->rcc_pllcfgr;
/* HSI, HSE, PLL enabled if specified.*/
RCC->CR = ccp->rcc_cr;
/* PLL activation polling if required.*/
if ((ccp->rcc_cr & RCC_CR_PLLON) != 0U) {
pll_wait_lock();
}
/* MCO and bus dividers first.*/
RCC->CFGR = (RCC->CFGR & RCC_CFGR_SW_Msk) | (ccp->rcc_cfgr & ~RCC_CFGR_SW_Msk);
/* Final flash ACR settings.*/
FLASH->ACR = ccp->flash_acr;
/* Final PWR modes.*/
PWR->CR1 = ccp->pwr_cr1;
PWR->CR2 = ccp->pwr_cr2;
PWR->CR3 = ccp->pwr_cr3;
PWR->CR4 = ccp->pwr_cr4;
PWR->CR5 = ccp->pwr_cr5;
/* Wait on LPR bit clear.*/
if ((ccp->pwr_cr1 & PWR_CR1_LPR) == 0U) {
while ((PWR->SR2 & PWR_SR2_REGLPF) != 0U) {
/* Waiting for the regulator to be ready.*/
}
}
/* Switching to the final clock source.*/
RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_SW_Msk) | (ccp->rcc_cfgr & RCC_CFGR_SW_Msk);
while ((RCC->CFGR & RCC_CFGR_SWS) != ((ccp->rcc_cfgr & RCC_CFGR_SW_Msk) << RCC_CFGR_SWS_Pos)) {
/* Waiting for clock switch.*/
}
return false;
}
#endif /* defined(HAL_LLD_USE_CLOCK_MANAGEMENT) */
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level HAL driver initialization.
*
* @notapi
*/
void hal_lld_init(void) {
#if defined(HAL_LLD_USE_CLOCK_MANAGEMENT)
if (hal_lld_clock_check_tree(&hal_clkcfg_default)) {
osalSysHalt("clkcfg");
}
#endif
/* DMA subsystems initialization.*/
#if defined(STM32_DMA_REQUIRED)
dmaInit();
#endif
/* NVIC initialization.*/
nvicInit();
/* IRQ subsystem initialization.*/
irqInit();
}
#if defined(HAL_LLD_USE_CLOCK_MANAGEMENT) || defined(__DOXYGEN__)
/**
* @brief STM32L4xx clocks and PLL initialization.
* @note All the involved constants come from the file @p board.h.
* @note This function should be invoked just after the system reset.
*
* @special
*/
void stm32_clock_init(void) {
#if !STM32_NO_INIT
/* Reset of all peripherals.
Note, GPIOs are not reset because initialized before this point in
board files.*/
rccResetAHB1(~0);
rccResetAHB2(~STM32_GPIO_EN_MASK);
rccResetAHB3(~0);
rccResetAPB1R1(~0);
rccResetAPB1R2(~0);
rccResetAPB2(~0);
/* SYSCFG clock enabled here because it is a multi-functional unit shared
among multiple drivers.*/
rccEnableAPB2(RCC_APB2ENR_SYSCFGEN, false);
/* PWR clock enable.*/
#if (HAL_USE_RTC == TRUE) && defined(RCC_APBENR1_RTCAPBEN)
rccEnableAPB1R1(RCC_APB1ENR1_PWREN | RCC_APB1ENR1_RTCAPBEN, false)
#else
rccEnableAPB1R1(RCC_APB1ENR1_PWREN, false)
#endif
/* Backup domain made accessible.*/
PWR->CR1 |= PWR_CR1_DBP;
/* Backup domain reset.*/
bd_reset();
/* Static clocks setup.*/
lse_init();
lsi_init();
/* Selecting the default clock/power/flash configuration.*/
if (hal_lld_clock_raw_switch(&hal_clkcfg_default)) {
osalSysHalt("clkswc");
}
/* Backup domain initializations.*/
bd_init();
#endif /* STM32_NO_INIT */
}
#else /* !defined(HAL_LLD_USE_CLOCK_MANAGEMENT) */
void stm32_clock_init(void) {
#if !STM32_NO_INIT
/* Reset of all peripherals.
Note, GPIOs are not reset because initialized before this point in
board files.*/
rccResetAHB1(~0);
rccResetAHB2(~STM32_GPIO_EN_MASK);
rccResetAHB3(~0);
rccResetAPB1R1(~0);
rccResetAPB1R2(~0);
rccResetAPB2(~0);
/* SYSCFG clock enabled here because it is a multi-functional unit shared
among multiple drivers.*/
rccEnableAPB2(RCC_APB2ENR_SYSCFGEN, false);
/* PWR clock enable.*/
#if (HAL_USE_RTC == TRUE) && defined(RCC_APBENR1_RTCAPBEN)
rccEnableAPB1R1(RCC_APB1ENR1_PWREN | RCC_APB1ENR1_RTCAPBEN, false)
#else
rccEnableAPB1R1(RCC_APB1ENR1_PWREN, false)
#endif
/* Core voltage setup, backup domain made accessible.*/
PWR->CR1 = STM32_VOS | PWR_CR1_DBP;
while ((PWR->SR2 & PWR_SR2_VOSF) != 0) /* Wait until regulator is */
; /* stable. */
/* Additional PWR configurations.*/
PWR->CR2 = STM32_PWR_CR2;
PWR->CR3 = STM32_PWR_CR3;
PWR->CR4 = STM32_PWR_CR4;
PWR->CR5 = STM32_CR5BITS;
/* Backup domain reset.*/
bd_reset();
/* Clocks setup.*/
lse_init();
lsi_init();
hsi16_init();
hsi48_init();
hse_init();
/* Backup domain initializations.*/
bd_init();
/* PLLs activation, if required.*/
pll_init();
/* Other clock-related settings (dividers, MCO etc).*/
RCC->CFGR = STM32_MCOPRE | STM32_MCOSEL | STM32_PPRE2 | STM32_PPRE1 |
STM32_HPRE;
/* CCIPR registers initialization, note.*/
RCC->CCIPR = STM32_ADC345SEL | STM32_ADC12SEL | STM32_CLK48SEL |
STM32_FDCANSEL | STM32_I2S23SEL | STM32_SAI1SEL |
STM32_LPTIM1SEL | STM32_I2C3SEL | STM32_I2C2SEL |
STM32_I2C1SEL | STM32_LPUART1SEL | STM32_UART5SEL |
STM32_UART4SEL | STM32_USART3SEL | STM32_USART2SEL |
STM32_USART1SEL;
RCC->CCIPR2 = STM32_QSPISEL | STM32_I2C4SEL;
/* Set flash WS's for SYSCLK source.*/
FLASH->ACR = FLASH_ACR_DBG_SWEN | FLASH_ACR_DCEN | FLASH_ACR_ICEN |
FLASH_ACR_PRFTEN | STM32_FLASHBITS;
while ((FLASH->ACR & FLASH_ACR_LATENCY_Msk) !=
(STM32_FLASHBITS & FLASH_ACR_LATENCY_Msk)) {
}
/* Switching to the configured SYSCLK source if it is different from HSI16.*/
#if STM32_SW != STM32_SW_HSI16
RCC->CFGR |= STM32_SW; /* Switches on the selected clock source. */
/* Wait until SYSCLK is stable.*/
while ((RCC->CFGR & RCC_CFGR_SWS) != (STM32_SW << 2))
;
#endif
#endif /* STM32_NO_INIT */
}
#endif /* !defined(HAL_LLD_USE_CLOCK_MANAGEMENT) */
#if defined(HAL_LLD_USE_CLOCK_MANAGEMENT) || defined(__DOXYGEN__)
/**
* @brief Switches to a different clock configuration
*
* @param[in] ccp pointer to clock a @p halclkcfg_t structure
* @return The clock switch result.
* @retval false if the clock switch succeeded
* @retval true if the clock switch failed
*
* @notapi
*/
bool hal_lld_clock_switch_mode(const halclkcfg_t *ccp) {
if (hal_lld_clock_check_tree(ccp)) {
return true;
}
if (hal_lld_clock_raw_switch(ccp)) {
return true;
}
return false;
}
/**
* @brief Returns the frequency of a clock point in Hz.
*
* @param[in] clkpt clock point to be returned
* @return The clock point frequency in Hz or zero if the
* frequency is unknown.
*
* @notapi
*/
halfreq_t hal_lld_get_clock_point(halclkpt_t clkpt) {
osalDbgAssert(clkpt < CLK_ARRAY_SIZE, "invalid clock point");
return clock_points[clkpt];
}
#endif /* defined(HAL_LLD_USE_CLOCK_MANAGEMENT) */
/** @} */