mbed library sources. Supersedes mbed-src.
Fork of mbed-dev by
Diff: targets/TARGET_NUVOTON/TARGET_M451/device/StdDriver/m451_clk.c
- Revision:
- 149:156823d33999
diff -r 21d94c44109e -r 156823d33999 targets/TARGET_NUVOTON/TARGET_M451/device/StdDriver/m451_clk.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/targets/TARGET_NUVOTON/TARGET_M451/device/StdDriver/m451_clk.c Fri Oct 28 11:17:30 2016 +0100 @@ -0,0 +1,751 @@ +/**************************************************************************//** + * @file clk.c + * @version V3.00 + * $Revision: 35 $ + * $Date: 15/08/11 10:26a $ + * @brief M451 series CLK driver source file + * + * @note + * Copyright (C) 2014~2015 Nuvoton Technology Corp. All rights reserved. + *****************************************************************************/ + +#include "M451Series.h" + +/** @addtogroup Standard_Driver Standard Driver + @{ +*/ + +/** @addtogroup CLK_Driver CLK Driver + @{ +*/ + +/** @addtogroup CLK_EXPORTED_FUNCTIONS CLK Exported Functions + @{ +*/ + +/** + * @brief Disable clock divider output function + * @param None + * @return None + * @details This function disable clock divider output function. + */ +void CLK_DisableCKO(void) +{ + /* Disable CKO clock source */ + CLK_DisableModuleClock(CLKO_MODULE); +} + +/** + * @brief This function enable clock divider output module clock, + * enable clock divider output function and set frequency selection. + * @param[in] u32ClkSrc is frequency divider function clock source. Including : + * - \ref CLK_CLKSEL1_CLKOSEL_HXT + * - \ref CLK_CLKSEL1_CLKOSEL_LXT + * - \ref CLK_CLKSEL1_CLKOSEL_HCLK + * - \ref CLK_CLKSEL1_CLKOSEL_HIRC + * @param[in] u32ClkDiv is divider output frequency selection. It could be 0~15. + * @param[in] u32ClkDivBy1En is clock divided by one enabled. + * @return None + * @details Output selected clock to CKO. The output clock frequency is divided by u32ClkDiv. \n + * The formula is: \n + * CKO frequency = (Clock source frequency) / 2^(u32ClkDiv + 1) \n + * This function is just used to set CKO clock. + * User must enable I/O for CKO clock output pin by themselves. \n + */ +void CLK_EnableCKO(uint32_t u32ClkSrc, uint32_t u32ClkDiv, uint32_t u32ClkDivBy1En) +{ + /* CKO = clock source / 2^(u32ClkDiv + 1) */ + CLK->CLKOCTL = CLK_CLKOCTL_CLKOEN_Msk | u32ClkDiv | (u32ClkDivBy1En << CLK_CLKOCTL_DIV1EN_Pos); + + /* Enable CKO clock source */ + CLK_EnableModuleClock(CLKO_MODULE); + + /* Select CKO clock source */ + CLK_SetModuleClock(CLKO_MODULE, u32ClkSrc, 0); +} + +/** + * @brief Enter to Power-down mode + * @param None + * @return None + * @details This function is used to let system enter to Power-down mode. \n + * The register write-protection function should be disabled before using this function. + */ +void CLK_PowerDown(void) +{ + /* Set the processor uses deep sleep as its low power mode */ + SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; + + /* Set system Power-down enabled and Power-down entry condition */ + CLK->PWRCTL |= (CLK_PWRCTL_PDEN_Msk | CLK_PWRCTL_PDWTCPU_Msk); + + /* Chip enter Power-down mode after CPU run WFI instruction */ + __WFI(); +} + +/** + * @brief Enter to Idle mode + * @param None + * @return None + * @details This function let system enter to Idle mode. \n + * The register write-protection function should be disabled before using this function. + */ +void CLK_Idle(void) +{ + /* Set the processor uses sleep as its low power mode */ + SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk; + + /* Set chip in idle mode because of WFI command */ + CLK->PWRCTL &= ~CLK_PWRCTL_PDEN_Msk; + + /* Chip enter idle mode after CPU run WFI instruction */ + __WFI(); +} + +/** + * @brief Get external high speed crystal clock frequency + * @param None + * @return External high frequency crystal frequency + * @details This function get external high frequency crystal frequency. The frequency unit is Hz. + */ +uint32_t CLK_GetHXTFreq(void) +{ + if(CLK->PWRCTL & CLK_PWRCTL_HXTEN_Msk) + return __HXT; + else + return 0; +} + + +/** + * @brief Get external low speed crystal clock frequency + * @param None + * @return External low speed crystal clock frequency + * @details This function get external low frequency crystal frequency. The frequency unit is Hz. + */ +uint32_t CLK_GetLXTFreq(void) +{ + if(CLK->PWRCTL & CLK_PWRCTL_LXTEN_Msk) + return __LXT; + else + return 0; +} + +/** + * @brief Get PCLK0 frequency + * @param None + * @return PCLK0 frequency + * @details This function get PCLK0 frequency. The frequency unit is Hz. + */ +uint32_t CLK_GetPCLK0Freq(void) +{ + SystemCoreClockUpdate(); + if(CLK->CLKSEL0 & CLK_CLKSEL0_PCLK0SEL_Msk) + return SystemCoreClock / 2; + else + return SystemCoreClock; +} + + +/** + * @brief Get PCLK1 frequency + * @param None + * @return PCLK1 frequency + * @details This function get PCLK1 frequency. The frequency unit is Hz. + */ +uint32_t CLK_GetPCLK1Freq(void) +{ + SystemCoreClockUpdate(); + if(CLK->CLKSEL0 & CLK_CLKSEL0_PCLK1SEL_Msk) + return SystemCoreClock / 2; + else + return SystemCoreClock; +} + + +/** + * @brief Get HCLK frequency + * @param None + * @return HCLK frequency + * @details This function get HCLK frequency. The frequency unit is Hz. + */ +uint32_t CLK_GetHCLKFreq(void) +{ + SystemCoreClockUpdate(); + return SystemCoreClock; +} + + +/** + * @brief Get CPU frequency + * @param None + * @return CPU frequency + * @details This function get CPU frequency. The frequency unit is Hz. + */ +uint32_t CLK_GetCPUFreq(void) +{ + SystemCoreClockUpdate(); + return SystemCoreClock; +} + + +/** + * @brief Set HCLK frequency + * @param[in] u32Hclk is HCLK frequency. The range of u32Hclk is 25 MHz ~ 72 MHz. + * @return HCLK frequency + * @details This function is used to set HCLK frequency. The frequency unit is Hz. \n + * It would configure PLL frequency to 50MHz ~ 144MHz, + * set HCLK clock divider as 2 and switch HCLK clock source to PLL. \n + * The register write-protection function should be disabled before using this function. + */ +uint32_t CLK_SetCoreClock(uint32_t u32Hclk) +{ + uint32_t u32HIRCSTB; + + /* Read HIRC clock source stable flag */ + u32HIRCSTB = CLK->STATUS & CLK_STATUS_HIRCSTB_Msk; + + /* The range of u32Hclk is 25 MHz ~ 72 MHz */ + if(u32Hclk > FREQ_72MHZ) + u32Hclk = FREQ_72MHZ; + if(u32Hclk < FREQ_25MHZ) + u32Hclk = FREQ_25MHZ; + + /* Switch HCLK clock source to HIRC clock for safe */ + CLK->PWRCTL |= CLK_PWRCTL_HIRCEN_Msk; + CLK_WaitClockReady(CLK_STATUS_HIRCSTB_Msk); + CLK->CLKSEL0 |= CLK_CLKSEL0_HCLKSEL_Msk; + CLK->CLKDIV0 &= (~CLK_CLKDIV0_HCLKDIV_Msk); + + /* Configure PLL setting if HXT clock is enabled */ + if(CLK->PWRCTL & CLK_PWRCTL_HXTEN_Msk) + u32Hclk = CLK_EnablePLL(CLK_PLLCTL_PLLSRC_HXT, (u32Hclk << 1)); + + /* Configure PLL setting if HXT clock is not enabled */ + else + { + u32Hclk = CLK_EnablePLL(CLK_PLLCTL_PLLSRC_HIRC, (u32Hclk << 1)); + + /* Read HIRC clock source stable flag */ + u32HIRCSTB = CLK->STATUS & CLK_STATUS_HIRCSTB_Msk; + } + + /* Select HCLK clock source to PLL, + Select HCLK clock source divider as 2 + and update system core clock + */ + CLK_SetHCLK(CLK_CLKSEL0_HCLKSEL_PLL, CLK_CLKDIV0_HCLK(2)); + + /* Disable HIRC if HIRC is disabled before setting core clock */ + if(u32HIRCSTB == 0) + CLK->PWRCTL &= ~CLK_PWRCTL_HIRCEN_Msk; + + /* Return actually HCLK frequency is PLL frequency divide 2 */ + return u32Hclk >> 1; +} + +/** + * @brief This function set HCLK clock source and HCLK clock divider + * @param[in] u32ClkSrc is HCLK clock source. Including : + * - \ref CLK_CLKSEL0_HCLKSEL_HXT + * - \ref CLK_CLKSEL0_HCLKSEL_LXT + * - \ref CLK_CLKSEL0_HCLKSEL_PLL + * - \ref CLK_CLKSEL0_HCLKSEL_LIRC + * - \ref CLK_CLKSEL0_HCLKSEL_HIRC + * @param[in] u32ClkDiv is HCLK clock divider. Including : + * - \ref CLK_CLKDIV0_HCLK(x) + * @return None + * @details This function set HCLK clock source and HCLK clock divider. \n + * The register write-protection function should be disabled before using this function. + */ +void CLK_SetHCLK(uint32_t u32ClkSrc, uint32_t u32ClkDiv) +{ + uint32_t u32HIRCSTB; + + /* Read HIRC clock source stable flag */ + u32HIRCSTB = CLK->STATUS & CLK_STATUS_HIRCSTB_Msk; + + /* Switch to HIRC for Safe. Avoid HCLK too high when applying new divider. */ + CLK->PWRCTL |= CLK_PWRCTL_HIRCEN_Msk; + CLK_WaitClockReady(CLK_STATUS_HIRCSTB_Msk); + CLK->CLKSEL0 = (CLK->CLKSEL0 & (~CLK_CLKSEL0_HCLKSEL_Msk)) | CLK_CLKSEL0_HCLKSEL_HIRC; + + /* Apply new Divider */ + CLK->CLKDIV0 = (CLK->CLKDIV0 & (~CLK_CLKDIV0_HCLKDIV_Msk)) | u32ClkDiv; + + /* Switch HCLK to new HCLK source */ + CLK->CLKSEL0 = (CLK->CLKSEL0 & (~CLK_CLKSEL0_HCLKSEL_Msk)) | u32ClkSrc; + + /* Update System Core Clock */ + SystemCoreClockUpdate(); + + /* Disable HIRC if HIRC is disabled before switching HCLK source */ + if(u32HIRCSTB == 0) + CLK->PWRCTL &= ~CLK_PWRCTL_HIRCEN_Msk; +} + +/** + * @brief This function set selected module clock source and module clock divider + * @param[in] u32ModuleIdx is module index. + * @param[in] u32ClkSrc is module clock source. + * @param[in] 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_WDTSEL_LXT | x | + * |\ref WDT_MODULE |\ref CLK_CLKSEL1_WDTSEL_PCLK0_DIV2048 | x | + * |\ref WDT_MODULE |\ref CLK_CLKSEL1_WDTSEL_LIRC | x | + * |\ref RTC_MODULE |\ref CLK_CLKSEL3_RTCSEL_LXT | x | + * |\ref RTC_MODULE |\ref CLK_CLKSEL3_RTCSEL_LIRC | x | + * |\ref TMR0_MODULE |\ref CLK_CLKSEL1_TMR0SEL_HXT | x | + * |\ref TMR0_MODULE |\ref CLK_CLKSEL1_TMR0SEL_LXT | x | + * |\ref TMR0_MODULE |\ref CLK_CLKSEL1_TMR0SEL_PCLK0 | x | + * |\ref TMR0_MODULE |\ref CLK_CLKSEL1_TMR0SEL_EXT_TRG | x | + * |\ref TMR0_MODULE |\ref CLK_CLKSEL1_TMR0SEL_LIRC | x | + * |\ref TMR0_MODULE |\ref CLK_CLKSEL1_TMR0SEL_HIRC | x | + * |\ref TMR1_MODULE |\ref CLK_CLKSEL1_TMR1SEL_HXT | x | + * |\ref TMR1_MODULE |\ref CLK_CLKSEL1_TMR1SEL_LXT | x | + * |\ref TMR1_MODULE |\ref CLK_CLKSEL1_TMR1SEL_PCLK0 | x | + * |\ref TMR1_MODULE |\ref CLK_CLKSEL1_TMR1SEL_EXT_TRG | x | + * |\ref TMR1_MODULE |\ref CLK_CLKSEL1_TMR1SEL_LIRC | x | + * |\ref TMR1_MODULE |\ref CLK_CLKSEL1_TMR1SEL_HIRC | x | + * |\ref TMR2_MODULE |\ref CLK_CLKSEL1_TMR2SEL_HXT | x | + * |\ref TMR2_MODULE |\ref CLK_CLKSEL1_TMR2SEL_LXT | x | + * |\ref TMR2_MODULE |\ref CLK_CLKSEL1_TMR2SEL_PCLK1 | x | + * |\ref TMR2_MODULE |\ref CLK_CLKSEL1_TMR2SEL_EXT_TRG | x | + * |\ref TMR2_MODULE |\ref CLK_CLKSEL1_TMR2SEL_LIRC | x | + * |\ref TMR2_MODULE |\ref CLK_CLKSEL1_TMR2SEL_HIRC | x | + * |\ref TMR3_MODULE |\ref CLK_CLKSEL1_TMR3SEL_HXT | x | + * |\ref TMR3_MODULE |\ref CLK_CLKSEL1_TMR3SEL_LXT | x | + * |\ref TMR3_MODULE |\ref CLK_CLKSEL1_TMR3SEL_PCLK1 | x | + * |\ref TMR3_MODULE |\ref CLK_CLKSEL1_TMR3SEL_EXT_TRG | x | + * |\ref TMR3_MODULE |\ref CLK_CLKSEL1_TMR3SEL_LIRC | x | + * |\ref TMR3_MODULE |\ref CLK_CLKSEL1_TMR3SEL_HIRC | x | + * |\ref CLKO_MODULE |\ref CLK_CLKSEL1_CLKOSEL_HXT | x | + * |\ref CLKO_MODULE |\ref CLK_CLKSEL1_CLKOSEL_LXT | x | + * |\ref CLKO_MODULE |\ref CLK_CLKSEL1_CLKOSEL_HCLK | x | + * |\ref CLKO_MODULE |\ref CLK_CLKSEL1_CLKOSEL_HIRC | x | + * |\ref SPI0_MODULE |\ref CLK_CLKSEL2_SPI0SEL_HXT | x | + * |\ref SPI0_MODULE |\ref CLK_CLKSEL2_SPI0SEL_PLL | x | + * |\ref SPI0_MODULE |\ref CLK_CLKSEL2_SPI0SEL_PCLK0 | x | + * |\ref SPI0_MODULE |\ref CLK_CLKSEL2_SPI0SEL_HIRC | x | + * |\ref SPI1_MODULE |\ref CLK_CLKSEL2_SPI1SEL_HXT | x | + * |\ref SPI1_MODULE |\ref CLK_CLKSEL2_SPI1SEL_PLL | x | + * |\ref SPI1_MODULE |\ref CLK_CLKSEL2_SPI1SEL_PCLK1 | x | + * |\ref SPI1_MODULE |\ref CLK_CLKSEL2_SPI1SEL_HIRC | x | + * |\ref SPI2_MODULE |\ref CLK_CLKSEL2_SPI2SEL_HXT | x | + * |\ref SPI2_MODULE |\ref CLK_CLKSEL2_SPI2SEL_PLL | x | + * |\ref SPI2_MODULE |\ref CLK_CLKSEL2_SPI2SEL_PCLK0 | x | + * |\ref SPI2_MODULE |\ref CLK_CLKSEL2_SPI2SEL_HIRC | x | + * |\ref UART0_MODULE |\ref CLK_CLKSEL1_UARTSEL_HXT |\ref CLK_CLKDIV0_UART(x) | + * |\ref UART0_MODULE |\ref CLK_CLKSEL1_UARTSEL_PLL |\ref CLK_CLKDIV0_UART(x) | + * |\ref UART0_MODULE |\ref CLK_CLKSEL1_UARTSEL_LXT |\ref CLK_CLKDIV0_UART(x) | + * |\ref UART0_MODULE |\ref CLK_CLKSEL1_UARTSEL_HIRC |\ref CLK_CLKDIV0_UART(x) | + * |\ref UART1_MODULE |\ref CLK_CLKSEL1_UARTSEL_HXT |\ref CLK_CLKDIV0_UART(x) | + * |\ref UART1_MODULE |\ref CLK_CLKSEL1_UARTSEL_PLL |\ref CLK_CLKDIV0_UART(x) | + * |\ref UART1_MODULE |\ref CLK_CLKSEL1_UARTSEL_LXT |\ref CLK_CLKDIV0_UART(x) | + * |\ref UART1_MODULE |\ref CLK_CLKSEL1_UARTSEL_HIRC |\ref CLK_CLKDIV0_UART(x) | + * |\ref UART2_MODULE |\ref CLK_CLKSEL1_UARTSEL_HXT |\ref CLK_CLKDIV0_UART(x) | + * |\ref UART2_MODULE |\ref CLK_CLKSEL1_UARTSEL_PLL |\ref CLK_CLKDIV0_UART(x) | + * |\ref UART2_MODULE |\ref CLK_CLKSEL1_UARTSEL_LXT |\ref CLK_CLKDIV0_UART(x) | + * |\ref UART2_MODULE |\ref CLK_CLKSEL1_UARTSEL_HIRC |\ref CLK_CLKDIV0_UART(x) | + * |\ref UART3_MODULE |\ref CLK_CLKSEL1_UARTSEL_HXT |\ref CLK_CLKDIV0_UART(x) | + * |\ref UART3_MODULE |\ref CLK_CLKSEL1_UARTSEL_LXT |\ref CLK_CLKDIV0_UART(x) | + * |\ref UART3_MODULE |\ref CLK_CLKSEL1_UARTSEL_PLL |\ref CLK_CLKDIV0_UART(x) | + * |\ref UART3_MODULE |\ref CLK_CLKSEL1_UARTSEL_HIRC |\ref CLK_CLKDIV0_UART(x) | + * |\ref USBH_MODULE | x |\ref CLK_CLKDIV0_USB(x) | + * |\ref USBD_MODULE | x |\ref CLK_CLKDIV0_USB(x) | + * |\ref OTG_MODULE | x |\ref CLK_CLKDIV0_USB(x) | + * |\ref EADC_MODULE | x |\ref CLK_CLKDIV0_EADC(x) | + * |\ref SC0_MODULE |\ref CLK_CLKSEL3_SC0SEL_HXT |\ref CLK_CLKDIV1_SC0(x) | + * |\ref SC0_MODULE |\ref CLK_CLKSEL3_SC0SEL_PLL |\ref CLK_CLKDIV1_SC0(x) | + * |\ref SC0_MODULE |\ref CLK_CLKSEL3_SC0SEL_PCLK0 |\ref CLK_CLKDIV1_SC0(x) | + * |\ref SC0_MODULE |\ref CLK_CLKSEL3_SC0SEL_HIRC |\ref CLK_CLKDIV1_SC0(x) | + * |\ref PWM0_MODULE |\ref CLK_CLKSEL2_PWM0SEL_PLL | x | + * |\ref PWM0_MODULE |\ref CLK_CLKSEL2_PWM0SEL_PCLK0 | x | + * |\ref PWM1_MODULE |\ref CLK_CLKSEL2_PWM1SEL_PLL | x | + * |\ref PWM1_MODULE |\ref CLK_CLKSEL2_PWM1SEL_PCLK1 | x | + * |\ref WWDT_MODULE |\ref CLK_CLKSEL1_WWDTSEL_PCLK0_DIV2048 | x | + * |\ref WWDT_MODULE |\ref CLK_CLKSEL1_WWDTSEL_LIRC | x | + */ +void CLK_SetModuleClock(uint32_t u32ModuleIdx, uint32_t u32ClkSrc, uint32_t u32ClkDiv) +{ + uint32_t u32sel = 0, u32div = 0; + + if(MODULE_CLKDIV_Msk(u32ModuleIdx) != MODULE_NoMsk) + { + /* Get clock divider control register address */ + u32div = (uint32_t)&CLK->CLKDIV0 + ((MODULE_CLKDIV(u32ModuleIdx)) * 4); + /* Apply new divider */ + M32(u32div) = (M32(u32div) & (~(MODULE_CLKDIV_Msk(u32ModuleIdx) << MODULE_CLKDIV_Pos(u32ModuleIdx)))) | u32ClkDiv; + } + + if(MODULE_CLKSEL_Msk(u32ModuleIdx) != MODULE_NoMsk) + { + /* Get clock select control register address */ + u32sel = (uint32_t)&CLK->CLKSEL0 + ((MODULE_CLKSEL(u32ModuleIdx)) * 4); + /* Set new clock selection setting */ + M32(u32sel) = (M32(u32sel) & (~(MODULE_CLKSEL_Msk(u32ModuleIdx) << MODULE_CLKSEL_Pos(u32ModuleIdx)))) | u32ClkSrc; + } +} + + +/** + * @brief Set SysTick clock source + * @param[in] u32ClkSrc is module clock source. Including: + * - \ref CLK_CLKSEL0_STCLKSEL_HXT + * - \ref CLK_CLKSEL0_STCLKSEL_LXT + * - \ref CLK_CLKSEL0_STCLKSEL_HXT_DIV2 + * - \ref CLK_CLKSEL0_STCLKSEL_HCLK_DIV2 + * - \ref CLK_CLKSEL0_STCLKSEL_HIRC_DIV2 + * @return None + * @details This function set SysTick clock source. \n + * The register write-protection function should be disabled before using this function. + */ +void CLK_SetSysTickClockSrc(uint32_t u32ClkSrc) +{ + CLK->CLKSEL0 = (CLK->CLKSEL0 & ~CLK_CLKSEL0_STCLKSEL_Msk) | u32ClkSrc; + +} + +/** + * @brief Enable clock source + * @param[in] u32ClkMask is clock source mask. Including : + * - \ref CLK_PWRCTL_HXTEN_Msk + * - \ref CLK_PWRCTL_LXTEN_Msk + * - \ref CLK_PWRCTL_HIRCEN_Msk + * - \ref CLK_PWRCTL_LIRCEN_Msk + * @return None + * @details This function enable clock source. \n + * The register write-protection function should be disabled before using this function. + */ +void CLK_EnableXtalRC(uint32_t u32ClkMask) +{ + CLK->PWRCTL |= u32ClkMask; +} + +/** + * @brief Disable clock source + * @param[in] u32ClkMask is clock source mask. Including : + * - \ref CLK_PWRCTL_HXTEN_Msk + * - \ref CLK_PWRCTL_LXTEN_Msk + * - \ref CLK_PWRCTL_HIRCEN_Msk + * - \ref CLK_PWRCTL_LIRCEN_Msk + * @return None + * @details This function disable clock source. \n + * The register write-protection function should be disabled before using this function. + */ +void CLK_DisableXtalRC(uint32_t u32ClkMask) +{ + CLK->PWRCTL &= ~u32ClkMask; +} + +/** + * @brief Enable module clock + * @param[in] u32ModuleIdx is module index. Including : + * - \ref PDMA_MODULE + * - \ref ISP_MODULE + * - \ref EBI_MODULE + * - \ref USBH_MODULE + * - \ref CRC_MODULE + * - \ref WDT_MODULE + * - \ref WWDT_MODULE + * - \ref RTC_MODULE + * - \ref TMR0_MODULE + * - \ref TMR1_MODULE + * - \ref TMR2_MODULE + * - \ref TMR3_MODULE + * - \ref CLKO_MODULE + * - \ref ACMP01_MODULE + * - \ref I2C0_MODULE + * - \ref I2C1_MODULE + * - \ref SPI0_MODULE + * - \ref SPI1_MODULE + * - \ref SPI2_MODULE + * - \ref UART0_MODULE + * - \ref UART1_MODULE + * - \ref UART2_MODULE + * - \ref UART3_MODULE + * - \ref CAN0_MODULE + * - \ref OTG_MODULE + * - \ref USBD_MODULE + * - \ref EADC_MODULE + * - \ref SC0_MODULE + * - \ref DAC_MODULE + * - \ref PWM0_MODULE + * - \ref PWM1_MODULE + * - \ref TK_MODULE + * @return None + * @details This function is used to enable module clock. + */ +void CLK_EnableModuleClock(uint32_t u32ModuleIdx) +{ + *(volatile uint32_t *)((uint32_t)&CLK->AHBCLK + (MODULE_APBCLK(u32ModuleIdx) * 4)) |= 1 << MODULE_IP_EN_Pos(u32ModuleIdx); +} + +/** + * @brief Disable module clock + * @param[in] u32ModuleIdx is module index. Including : + * - \ref PDMA_MODULE + * - \ref ISP_MODULE + * - \ref EBI_MODULE + * - \ref USBH_MODULE + * - \ref CRC_MODULE + * - \ref WDT_MODULE + * - \ref WWDT_MODULE + * - \ref RTC_MODULE + * - \ref TMR0_MODULE + * - \ref TMR1_MODULE + * - \ref TMR2_MODULE + * - \ref TMR3_MODULE + * - \ref CLKO_MODULE + * - \ref ACMP01_MODULE + * - \ref I2C0_MODULE + * - \ref I2C1_MODULE + * - \ref SPI0_MODULE + * - \ref SPI1_MODULE + * - \ref SPI2_MODULE + * - \ref UART0_MODULE + * - \ref UART1_MODULE + * - \ref UART2_MODULE + * - \ref UART3_MODULE + * - \ref CAN0_MODULE + * - \ref OTG_MODULE + * - \ref USBD_MODULE + * - \ref EADC_MODULE + * - \ref SC0_MODULE + * - \ref DAC_MODULE + * - \ref PWM0_MODULE + * - \ref PWM1_MODULE + * - \ref TK_MODULE + * @return None + * @details This function is used to disable module clock. + */ +void CLK_DisableModuleClock(uint32_t u32ModuleIdx) +{ + *(volatile uint32_t *)((uint32_t)&CLK->AHBCLK + (MODULE_APBCLK(u32ModuleIdx) * 4)) &= ~(1 << MODULE_IP_EN_Pos(u32ModuleIdx)); +} + + +/** + * @brief Set PLL frequency + * @param[in] u32PllClkSrc is PLL clock source. Including : + * - \ref CLK_PLLCTL_PLLSRC_HXT + * - \ref CLK_PLLCTL_PLLSRC_HIRC + * @param[in] u32PllFreq is PLL frequency. + * @return PLL frequency + * @details This function is used to configure PLLCTL register to set specified PLL frequency. \n + * The register write-protection function should be disabled before using this function. + */ +uint32_t CLK_EnablePLL(uint32_t u32PllClkSrc, uint32_t u32PllFreq) +{ + uint32_t u32PllSrcClk, u32NR, u32NF, u32NO, u32CLK_SRC; + uint32_t u32Tmp, u32Tmp2, u32Tmp3, u32Min, u32MinNF, u32MinNR; + + /* Disable PLL first to avoid unstable when setting PLL */ + CLK_DisablePLL(); + + /* PLL source clock is from HXT */ + if(u32PllClkSrc == CLK_PLLCTL_PLLSRC_HXT) + { + /* Enable HXT clock */ + CLK->PWRCTL |= CLK_PWRCTL_HXTEN_Msk; + + /* Wait for HXT clock ready */ + CLK_WaitClockReady(CLK_STATUS_HXTSTB_Msk); + + /* Select PLL source clock from HXT */ + u32CLK_SRC = CLK_PLLCTL_PLLSRC_HXT; + u32PllSrcClk = __HXT; + + /* u32NR start from 2 */ + u32NR = 2; + } + + /* PLL source clock is from HIRC */ + else + { + /* Enable HIRC clock */ + CLK->PWRCTL |= CLK_PWRCTL_HIRCEN_Msk; + + /* Wait for HIRC clock ready */ + CLK_WaitClockReady(CLK_STATUS_HIRCSTB_Msk); + + /* Select PLL source clock from HIRC */ + u32CLK_SRC = CLK_PLLCTL_PLLSRC_HIRC; + u32PllSrcClk = __HIRC; + + /* u32NR start from 4 when FIN = 22.1184MHz to avoid calculation overflow */ + u32NR = 4; + } + + /* Select "NO" according to request frequency */ + if((u32PllFreq <= FREQ_500MHZ) && (u32PllFreq > FREQ_250MHZ)) + { + u32NO = 0; + } + else if((u32PllFreq <= FREQ_250MHZ) && (u32PllFreq > FREQ_125MHZ)) + { + u32NO = 1; + u32PllFreq = u32PllFreq << 1; + } + else if((u32PllFreq <= FREQ_125MHZ) && (u32PllFreq >= FREQ_50MHZ)) + { + u32NO = 3; + u32PllFreq = u32PllFreq << 2; + } + else + { + /* Wrong frequency request. Just return default setting. */ + goto lexit; + } + + /* Find best solution */ + u32Min = (uint32_t) - 1; + u32MinNR = 0; + u32MinNF = 0; + for(; u32NR <= 33; u32NR++) + { + u32Tmp = u32PllSrcClk / u32NR; + if((u32Tmp > 1600000) && (u32Tmp < 16000000)) + { + for(u32NF = 2; u32NF <= 513; u32NF++) + { + u32Tmp2 = u32Tmp * u32NF; + if((u32Tmp2 >= 200000000) && (u32Tmp2 <= 500000000)) + { + u32Tmp3 = (u32Tmp2 > u32PllFreq) ? u32Tmp2 - u32PllFreq : u32PllFreq - u32Tmp2; + if(u32Tmp3 < u32Min) + { + u32Min = u32Tmp3; + u32MinNR = u32NR; + u32MinNF = u32NF; + + /* Break when get good results */ + if(u32Min == 0) + break; + } + } + } + } + } + + /* Enable and apply new PLL setting. */ + CLK->PLLCTL = u32CLK_SRC | (u32NO << 14) | ((u32MinNR - 2) << 9) | (u32MinNF - 2); + + /* Wait for PLL clock stable */ + CLK_WaitClockReady(CLK_STATUS_PLLSTB_Msk); + + /* Return actual PLL output clock frequency */ + return u32PllSrcClk / ((u32NO + 1) * u32MinNR) * u32MinNF; + +lexit: + + /* Apply default PLL setting and return */ + if(u32PllClkSrc == CLK_PLLCTL_PLLSRC_HXT) + CLK->PLLCTL = CLK_PLLCTL_72MHz_HXT; /* 72MHz */ + else + CLK->PLLCTL = CLK_PLLCTL_72MHz_HIRC; /* 71.8848MHz */ + + /* Wait for PLL clock stable */ + CLK_WaitClockReady(CLK_STATUS_PLLSTB_Msk); + + return CLK_GetPLLClockFreq(); + +} + +/** + * @brief Disable PLL + * @param None + * @return None + * @details This function set PLL in Power-down mode. \n + * The register write-protection function should be disabled before using this function. + */ +void CLK_DisablePLL(void) +{ + CLK->PLLCTL |= CLK_PLLCTL_PD_Msk; +} + + +/** + * @brief This function check selected clock source status + * @param[in] u32ClkMask is selected clock source. Including : + * - \ref CLK_STATUS_HXTSTB_Msk + * - \ref CLK_STATUS_LXTSTB_Msk + * - \ref CLK_STATUS_HIRCSTB_Msk + * - \ref CLK_STATUS_LIRCSTB_Msk + * - \ref CLK_STATUS_PLLSTB_Msk + * @retval 0 clock is not stable + * @retval 1 clock is stable + * @details To wait for clock ready by specified clock source stable flag or timeout (~300ms) + */ +uint32_t CLK_WaitClockReady(uint32_t u32ClkMask) +{ + int32_t i32TimeOutCnt = 2160000; + + while((CLK->STATUS & u32ClkMask) != u32ClkMask) + { + if(i32TimeOutCnt-- <= 0) + return 0; + } + + return 1; +} + +/** + * @brief Enable System Tick counter + * @param[in] u32ClkSrc is System Tick clock source. Including: + * - \ref CLK_CLKSEL0_STCLKSEL_HXT + * - \ref CLK_CLKSEL0_STCLKSEL_LXT + * - \ref CLK_CLKSEL0_STCLKSEL_HXT_DIV2 + * - \ref CLK_CLKSEL0_STCLKSEL_HCLK_DIV2 + * - \ref CLK_CLKSEL0_STCLKSEL_HIRC_DIV2 + * - \ref CLK_CLKSEL0_STCLKSEL_HCLK + * @param[in] u32Count is System Tick reload value. It could be 0~0xFFFFFF. + * @return None + * @details This function set System Tick clock source, reload value, enable System Tick counter and interrupt. \n + * The register write-protection function should be disabled before using this function. + */ +void CLK_EnableSysTick(uint32_t u32ClkSrc, uint32_t u32Count) +{ + /* Set System Tick counter disabled */ + SysTick->CTRL = 0; + + /* Set System Tick clock source */ + if( u32ClkSrc == CLK_CLKSEL0_STCLKSEL_HCLK ) + SysTick->CTRL |= SysTick_CTRL_CLKSOURCE_Msk; + else + CLK->CLKSEL0 = (CLK->CLKSEL0 & ~CLK_CLKSEL0_STCLKSEL_Msk) | u32ClkSrc; + + /* Set System Tick reload value */ + SysTick->LOAD = u32Count; + + /* Clear System Tick current value and counter flag */ + SysTick->VAL = 0; + + /* Set System Tick interrupt enabled and counter enabled */ + SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk; +} + +/** + * @brief Disable System Tick counter + * @param None + * @return None + * @details This function disable System Tick counter. + */ +void CLK_DisableSysTick(void) +{ + /* Set System Tick counter disabled */ + SysTick->CTRL = 0; +} + + +/*@}*/ /* end of group CLK_EXPORTED_FUNCTIONS */ + +/*@}*/ /* end of group CLK_Driver */ + +/*@}*/ /* end of group Standard_Driver */ + +/*** (C) COPYRIGHT 2014~2015 Nuvoton Technology Corp. ***/