rtt-f030/bsp/nuvoton_m05x/Libraries/StdDriver/src/clk.c

471 lines
16 KiB
C

/**************************************************************************//**
* @file clk.c
* @version V3.00
* $Revision: 15 $
* $Date: 14/01/28 10:49a $
* @brief M051 series CLK driver source file
*
* @note
* Copyright (C) 2013 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include "M051Series.h"
/** @addtogroup M051_Device_Driver M051 Device Driver
@{
*/
/** @addtogroup M051_CLK_Driver CLK Driver
@{
*/
/** @addtogroup M051_CLK_EXPORTED_FUNCTIONS CLK Exported Functions
@{
*/
/**
* @brief This function disable frequency output function.
* @return None
*/
void CLK_DisableCKO(void)
{
/* Disable CKO clock source */
CLK_DisableModuleClock(FDIV_MODULE);
}
/**
* @brief This function enable frequency divider module clock,
* enable frequency divider clock function and configure frequency divider.
* @param u32ClkSrc is frequency divider function clock source. Including :
* - \ref CLK_CLKSEL2_FRQDIV_S_HXT
* - \ref CLK_CLKSEL2_FRQDIV_S_LIRC
* - \ref CLK_CLKSEL2_FRQDIV_S_HCLK
* - \ref CLK_CLKSEL2_FRQDIV_S_HIRC
* @param u32ClkDiv is divider output frequency selection.
* @param u32ClkDivBy1En is frequency divided by one enable.
* @return None
*
* @details Output selected clock to CKO. The output clock frequency is divided by u32ClkDiv.
* The formula is:
* CKO frequency = (Clock source frequency) / 2^(u32ClkDiv + 1)
* This function is just used to set CKO clock.
* User must enable I/O for CKO clock output pin by themselves.
*/
void CLK_EnableCKO(uint32_t u32ClkSrc, uint32_t u32ClkDiv, uint32_t u32ClkDivBy1En)
{
/* CKO = clock source / 2^(u32ClkDiv + 1) */
CLK->FRQDIV = CLK_FRQDIV_DIVIDER_EN_Msk | u32ClkDiv | u32ClkDivBy1En << CLK_FRQDIV_DIVIDER1_Pos;
/* Enable CKO clock source */
CLK_EnableModuleClock(FDIV_MODULE);
/* Select CKO clock source */
CLK_SetModuleClock(FDIV_MODULE, u32ClkSrc, 0);
}
/**
* @brief This function let system enter to Power-down mode.
* @return None
*/
void CLK_PowerDown(void)
{
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
CLK->PWRCON |= (CLK_PWRCON_PWR_DOWN_EN_Msk | CLK_PWRCON_PD_WAIT_CPU_Msk);
__WFI();
}
/**
* @brief This function let system enter to Idle mode.
* @return None
*/
void CLK_Idle(void)
{
SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
CLK->PWRCON &= ~CLK_PWRCON_PWR_DOWN_EN_Msk;
__WFI();
}
/**
* @brief This function get external high frequency crystal frequency. The frequency unit is Hz.
* @return External high frequency crystal frequency
*/
uint32_t CLK_GetHXTFreq(void)
{
if(CLK->PWRCON & CLK_PWRCON_XTL12M_EN_Msk)
return __HXT;
else
return 0;
}
/**
* @brief This function get HCLK frequency. The frequency unit is Hz.
* @return HCLK frequency
*/
uint32_t CLK_GetHCLKFreq(void)
{
SystemCoreClockUpdate();
return SystemCoreClock;
}
/**
* @brief This function get CPU frequency. The frequency unit is Hz.
* @return CPU frequency
*/
uint32_t CLK_GetCPUFreq(void)
{
SystemCoreClockUpdate();
return SystemCoreClock;
}
/**
* @brief This function set HCLK frequency. The frequency unit is Hz. The range of u32Hclk is 16 ~ 32 MHz
* @param u32Hclk is HCLK frequency
* @return HCLK frequency
*/
uint32_t CLK_SetCoreClock(uint32_t u32Hclk)
{
if(u32Hclk > FREQ_50MHZ)
u32Hclk = FREQ_50MHZ;
else if(u32Hclk < FREQ_25MHZ)
u32Hclk = FREQ_25MHZ;
if(CLK->PWRCON & CLK_PWRCON_XTL12M_EN_Msk)
u32Hclk = CLK_EnablePLL(CLK_PLLCON_PLL_SRC_HXT, u32Hclk);
else
u32Hclk = CLK_EnablePLL(CLK_PLLCON_PLL_SRC_HIRC, u32Hclk);
CLK_SetHCLK(CLK_CLKSEL0_HCLK_S_PLL, CLK_CLKDIV_HCLK(1));
return u32Hclk;
}
/**
* @brief This function set HCLK clock source and HCLK clock divider
* @param u32ClkSrc is HCLK clock source. Including :
* - \ref CLK_CLKSEL0_HCLK_S_HXT
* - \ref CLK_CLKSEL0_HCLK_S_PLL
* - \ref CLK_CLKSEL0_HCLK_S_LIRC
* - \ref CLK_CLKSEL0_HCLK_S_HIRC
* @param u32ClkDiv is HCLK clock divider. Including :
* - \ref CLK_CLKDIV_HCLK(x)
* @return None
*/
void CLK_SetHCLK(uint32_t u32ClkSrc, uint32_t u32ClkDiv)
{
CLK->CLKSEL0 = (CLK->CLKSEL0 & ~CLK_CLKSEL0_HCLK_S_Msk) | u32ClkSrc;
CLK->CLKDIV = (CLK->CLKDIV & ~CLK_CLKDIV_HCLK_N_Msk) | u32ClkDiv;
SystemCoreClockUpdate();
}
/**
* @brief This function set selected module clock source and module clock divider
* @param u32ModuleIdx is module index.
* @param u32ClkSrc is module clock source.
* @param u32ClkDiv is module clock divider.
* @return None
* @details Valid parameter combinations listed in following table:
*
* |Module index |Clock source |Divider |
* | :---------------- | :----------------------------------- | :--------------------- |
* |\ref WDT_MODULE |\ref CLK_CLKSEL1_WDT_S_HCLK_DIV2048 | x |
* |\ref WDT_MODULE |\ref CLK_CLKSEL1_WDT_S_LIRC | x |
* |\ref ADC_MODULE |\ref CLK_CLKSEL1_ADC_S_HXT |\ref CLK_CLKDIV_ADC(x) |
* |\ref ADC_MODULE |\ref CLK_CLKSEL1_ADC_S_PLL |\ref CLK_CLKDIV_ADC(x) |
* |\ref ADC_MODULE |\ref CLK_CLKSEL1_ADC_S_HCLK |\ref CLK_CLKDIV_ADC(x) |
* |\ref ADC_MODULE |\ref CLK_CLKSEL1_ADC_S_HIRC |\ref CLK_CLKDIV_ADC(x) |
* |\ref SPI0_MODULE |\ref CLK_CLKSEL1_SPI0_S_HCLK | x |
* |\ref SPI0_MODULE |\ref CLK_CLKSEL1_SPI0_S_PLL | x |
* |\ref SPI1_MODULE |\ref CLK_CLKSEL1_SPI1_S_HCLK | x |
* |\ref SPI1_MODULE |\ref CLK_CLKSEL1_SPI1_S_PLL | x |
* |\ref TMR0_MODULE |\ref CLK_CLKSEL1_TMR0_S_HXT | x |
* |\ref TMR0_MODULE |\ref CLK_CLKSEL1_TMR0_S_HCLK | x |
* |\ref TMR0_MODULE |\ref CLK_CLKSEL1_TMR0_S_T0 | x |
* |\ref TMR0_MODULE |\ref CLK_CLKSEL1_TMR0_S_LIRC | x |
* |\ref TMR0_MODULE |\ref CLK_CLKSEL1_TMR0_S_HIRC | x |
* |\ref TMR1_MODULE |\ref CLK_CLKSEL1_TMR0_S_HXT | x |
* |\ref TMR1_MODULE |\ref CLK_CLKSEL1_TMR0_S_HCLK | x |
* |\ref TMR1_MODULE |\ref CLK_CLKSEL1_TMR0_S_T1 | x |
* |\ref TMR1_MODULE |\ref CLK_CLKSEL1_TMR0_S_LIRC | x |
* |\ref TMR1_MODULE |\ref CLK_CLKSEL1_TMR0_S_HIRC | x |
* |\ref TMR2_MODULE |\ref CLK_CLKSEL1_TMR2_S_HXT | x |
* |\ref TMR2_MODULE |\ref CLK_CLKSEL1_TMR2_S_HCLK | x |
* |\ref TMR2_MODULE |\ref CLK_CLKSEL1_TMR2_S_T2 | x |
* |\ref TMR2_MODULE |\ref CLK_CLKSEL1_TMR2_S_LIRC | x |
* |\ref TMR2_MODULE |\ref CLK_CLKSEL1_TMR2_S_HIRC | x |
* |\ref TMR3_MODULE |\ref CLK_CLKSEL1_TMR3_S_HXT | x |
* |\ref TMR3_MODULE |\ref CLK_CLKSEL1_TMR3_S_HCLK | x |
* |\ref TMR3_MODULE |\ref CLK_CLKSEL1_TMR3_S_T3 | x |
* |\ref TMR3_MODULE |\ref CLK_CLKSEL1_TMR3_S_LIRC | x |
* |\ref TMR3_MODULE |\ref CLK_CLKSEL1_TMR3_S_HIRC | x |
* |\ref UART0_MODULE |\ref CLK_CLKSEL1_UART_S_HXT |\ref CLK_CLKDIV_UART(x) |
* |\ref UART0_MODULE |\ref CLK_CLKSEL1_UART_S_PLL |\ref CLK_CLKDIV_UART(x) |
* |\ref UART0_MODULE |\ref CLK_CLKSEL1_UART_S_HIRC |\ref CLK_CLKDIV_UART(x) |
* |\ref UART1_MODULE |\ref CLK_CLKSEL1_UART_S_HXT |\ref CLK_CLKDIV_UART(x) |
* |\ref UART1_MODULE |\ref CLK_CLKSEL1_UART_S_PLL |\ref CLK_CLKDIV_UART(x) |
* |\ref UART1_MODULE |\ref CLK_CLKSEL1_UART_S_HIRC |\ref CLK_CLKDIV_UART(x) |
* |\ref PWM01_MODULE |\ref CLK_CLKSEL1_PWM01_S_HXT | x |
* |\ref PWM01_MODULE |\ref CLK_CLKSEL1_PWM01_S_LIRC | x |
* |\ref PWM01_MODULE |\ref CLK_CLKSEL1_PWM01_S_HCLK | x |
* |\ref PWM01_MODULE |\ref CLK_CLKSEL1_PWM01_S_HIRC | x |
* |\ref PWM23_MODULE |\ref CLK_CLKSEL1_PWM23_S_HXT | x |
* |\ref PWM23_MODULE |\ref CLK_CLKSEL1_PWM23_S_LIRC | x |
* |\ref PWM23_MODULE |\ref CLK_CLKSEL1_PWM23_S_HCLK | x |
* |\ref PWM23_MODULE |\ref CLK_CLKSEL1_PWM23_S_HIRC | x |
* |\ref FDIV_MODULE |\ref CLK_CLKSEL2_FRQDIV_S_HXT | x |
* |\ref FDIV_MODULE |\ref CLK_CLKSEL2_FRQDIV_S_LIRC | x |
* |\ref FDIV_MODULE |\ref CLK_CLKSEL2_FRQDIV_S_HCLK | x |
* |\ref FDIV_MODULE |\ref CLK_CLKSEL2_FRQDIV_S_HIRC | x
* |\ref PWM45_MODULE |\ref CLK_CLKSEL2_PWM45_S_HXT | x |
* |\ref PWM45_MODULE |\ref CLK_CLKSEL2_PWM45_S_LIRC | x |
* |\ref PWM45_MODULE |\ref CLK_CLKSEL2_PWM45_S_HCLK | x |
* |\ref PWM45_MODULE |\ref CLK_CLKSEL2_PWM45_S_HIRC | x |
* |\ref PWM67_MODULE |\ref CLK_CLKSEL2_PWM67_S_HXT | x |
* |\ref PWM67_MODULE |\ref CLK_CLKSEL2_PWM67_S_LIRC | x |
* |\ref PWM67_MODULE |\ref CLK_CLKSEL2_PWM67_S_HCLK | x |
* |\ref PWM67_MODULE |\ref CLK_CLKSEL2_PWM67_S_HIRC | x |
* |\ref WWDT_MODULE |\ref CLK_CLKSEL1_WWDT_S_HCLK_DIV2048 | x |
* |\ref WWDT_MODULE |\ref CLK_CLKSEL1_WWDT_S_LIRC | x |
*/
void CLK_SetModuleClock(uint32_t u32ModuleIdx, uint32_t u32ClkSrc, uint32_t u32ClkDiv)
{
uint32_t u32tmp = 0, u32sel = 0, u32div = 0;
if(MODULE_CLKSEL_Msk(u32ModuleIdx) != MODULE_NoMsk)
{
u32sel = (uint32_t)&CLK->CLKSEL0 + ((MODULE_CLKSEL(u32ModuleIdx)) * 4);
u32tmp = *(volatile uint32_t *)(u32sel);
u32tmp = u32tmp & ~(MODULE_CLKSEL_Msk(u32ModuleIdx) << MODULE_CLKSEL_Pos(u32ModuleIdx)) | u32ClkSrc;
*(volatile uint32_t *)(u32sel) = u32tmp;
}
if(MODULE_CLKDIV_Msk(u32ModuleIdx) != MODULE_NoMsk)
{
u32div = (uint32_t)&CLK->CLKDIV + ((MODULE_CLKDIV(u32ModuleIdx)) * 4);
u32tmp = *(volatile uint32_t *)(u32div);
u32tmp = (u32tmp & ~MODULE_CLKDIV_Msk(u32ModuleIdx) << MODULE_CLKDIV_Pos(u32ModuleIdx)) | u32ClkDiv;
*(volatile uint32_t *)(u32div) = u32tmp;
}
}
/**
* @brief This function set systick clock source
* @param u32ClkSrc is module clock source. Including
* - \ref CLK_CLKSEL0_STCLK_S_HXT
* - \ref CLK_CLKSEL0_STCLK_S_HXT_DIV2
* - \ref CLK_CLKSEL0_STCLK_S_HCLK_DIV2
* - \ref CLK_CLKSEL0_STCLK_S_HIRC_DIV2
* @return None
*/
void CLK_SetSysTickClockSrc(uint32_t u32ClkSrc)
{
CLK->CLKSEL0 = (CLK->CLKSEL0 & ~CLK_CLKSEL0_STCLK_S_Msk) | u32ClkSrc;
}
/**
* @brief This function enable clock source
* @param u32ClkMask is clock source mask. Including :
* - \ref CLK_PWRCON_XTL12M_EN_Msk
* - \ref CLK_PWRCON_OSC22M_EN_Msk
* - \ref CLK_PWRCON_OSC10K_EN_Msk
* @return None
*/
void CLK_EnableXtalRC(uint32_t u32ClkMask)
{
CLK->PWRCON |= u32ClkMask;
}
/**
* @brief This function disable clock source
* @param u32ClkMask is clock source mask. Including :
* - \ref CLK_PWRCON_XTL12M_EN_Msk
* - \ref CLK_PWRCON_OSC22M_EN_Msk
* - \ref CLK_PWRCON_OSC10K_EN_Msk
* @return None
*/
void CLK_DisableXtalRC(uint32_t u32ClkMask)
{
CLK->PWRCON &= ~u32ClkMask;
}
/**
* @brief This function enable module clock
* @param u32ModuleIdx is module index. Including :
* - \ref WDT_MODULE
* - \ref TMR0_MODULE
* - \ref TMR1_MODULE
* - \ref TMR2_MODULE
* - \ref TMR3_MODULE
* - \ref FDIV_MODULE
* - \ref I2C0_MODULE
* - \ref I2C1_MODULE
* - \ref SPI0_MODULE
* - \ref SPI1_MODULE
* - \ref UART0_MODULE
* - \ref UART1_MODULE
* - \ref PWM01_MODULE
* - \ref PWM23_MODULE
* - \ref PWM45_MODULE
* - \ref PWM67_MODULE
* - \ref ADC_MODULE
* - \ref ACMP01_MODULE
* - \ref ACMP23_MODULE
* @return None
*/
void CLK_EnableModuleClock(uint32_t u32ModuleIdx)
{
*(volatile uint32_t *)((uint32_t)&CLK->APBCLK + (MODULE_APBCLK(u32ModuleIdx) * 4)) |= 1 << MODULE_IP_EN_Pos(u32ModuleIdx);
}
/**
* @brief This function disable module clock
* @param u32ModuleIdx is module index
* - \ref WDT_MODULE
* - \ref TMR0_MODULE
* - \ref TMR1_MODULE
* - \ref TMR2_MODULE
* - \ref TMR3_MODULE
* - \ref FDIV_MODULE
* - \ref I2C0_MODULE
* - \ref I2C1_MODULE
* - \ref SPI0_MODULE
* - \ref SPI1_MODULE
* - \ref UART0_MODULE
* - \ref UART1_MODULE
* - \ref PWM01_MODULE
* - \ref PWM23_MODULE
* - \ref PWM45_MODULE
* - \ref PWM67_MODULE
* - \ref ADC_MODULE
* - \ref ACMP01_MODULE
* - \ref ACMP23_MODULE
* @return None
*/
void CLK_DisableModuleClock(uint32_t u32ModuleIdx)
{
*(volatile uint32_t *)((uint32_t)&CLK->APBCLK + (MODULE_APBCLK(u32ModuleIdx) * 4)) &= ~(1 << MODULE_IP_EN_Pos(u32ModuleIdx));
}
/**
* @brief This function set PLL frequency
* @param u32PllClkSrc is PLL clock source. Including :
* - \ref CLK_PLLCON_PLL_SRC_HXT
* - \ref CLK_PLLCON_PLL_SRC_HIRC
* @param u32PllFreq is PLL frequency
* @return PLL frequency
*/
uint32_t CLK_EnablePLL(uint32_t u32PllClkSrc, uint32_t u32PllFreq)
{
uint32_t u32PllSrcClk, u32PLLReg, u32NR, u32NF, u32NO;
if(u32PllClkSrc == CLK_PLLCON_PLL_SRC_HXT)
{
/* PLL source clock from HXT */
CLK->PLLCON &= ~CLK_PLLCON_PLL_SRC_Msk;
u32PllSrcClk = __HXT;
}
else
{
/* PLL source clock from HIRC */
CLK->PLLCON |= CLK_PLLCON_PLL_SRC_Msk;
u32PllSrcClk = __HIRC;
}
if((u32PllFreq <= FREQ_200MHZ) && (u32PllFreq > FREQ_100MHZ))
{
u32NO = 0;
}
else if((u32PllFreq <= FREQ_100MHZ) && (u32PllFreq > FREQ_50MHZ))
{
u32NO = 1;
u32PllFreq = u32PllFreq << 1;
}
else if((u32PllFreq <= FREQ_50MHZ) && (u32PllFreq >= FREQ_25MHZ))
{
u32NO = 3;
u32PllFreq = u32PllFreq << 2;
}
else
{
if(u32PllClkSrc == CLK_PLLCON_PLL_SRC_HXT)
CLK->PLLCON = 0xC22E;
else
CLK->PLLCON = 0xD66F;
CLK_WaitClockReady(CLK_CLKSTATUS_PLL_STB_Msk);
return CLK_GetPLLClockFreq();
}
u32NF = u32PllFreq / 1000000;
u32NR = u32PllSrcClk / 1000000;
while(1)
{
if((u32NR & 0x01) || (u32NF & 0x01) || (u32NR == 2) || (u32NF == 2))
{
break;
}
else
{
u32NR >>= 1;
u32NF >>= 1;
}
}
u32PLLReg = (u32NO << 14) | ((u32NR - 2) << 9) | (u32NF - 2);
CLK->PLLCON = (CLK->PLLCON & ~(CLK_PLLCON_FB_DV_Msk | CLK_PLLCON_IN_DV_Msk | CLK_PLLCON_OUT_DV_Msk)) | u32PLLReg;
CLK->PLLCON &= ~(CLK_PLLCON_PD_Msk | CLK_PLLCON_OE_Msk);
CLK_WaitClockReady(CLK_CLKSTATUS_PLL_STB_Msk);
return ((u32PllSrcClk * u32NF) / (u32NR * (u32NO + 1)));
}
/**
* @brief This function disable PLL
* @param None
* @return None
*/
void CLK_DisablePLL(void)
{
CLK->PLLCON |= CLK_PLLCON_PD_Msk;
}
/**
* @brief This function check selected clock source status
* @param u32ClkMask is selected clock source. Including :
* - \ref CLK_CLKSTATUS_OSC22M_STB_Msk
* - \ref CLK_CLKSTATUS_OSC10K_STB_Msk
* - \ref CLK_CLKSTATUS_XTL12M_STB_Msk
* - \ref CLK_CLKSTATUS_PLL_STB_Msk
*
* @return None
*/
void CLK_WaitClockReady(uint32_t u32ClkMask)
{
int32_t i32TimeOutCnt;
i32TimeOutCnt = __HSI / 200; /* About 5ms */
while((CLK->CLKSTATUS & u32ClkMask) != u32ClkMask)
{
if(i32TimeOutCnt-- <= 0)
break;
}
}
/*@}*/ /* end of group M051_CLK_EXPORTED_FUNCTIONS */
/*@}*/ /* end of group M051_CLK_Driver */
/*@}*/ /* end of group M051_Device_Driver */
/*** (C) COPYRIGHT 2013 Nuvoton Technology Corp. ***/