| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593 |
- /*
- * Copyright (C) 2010 by Ulrich Prinz (uprinz2@netscape.net)
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
- * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * For additional information see http://www.ethernut.de/
- */
- /*
- * \verbatim
- * $Id: stm32f1_clk.c 5435 2013-10-24 18:51:00Z u_bonnes $
- * \endverbatim
- */
- #include <cfg/arch.h>
- #include <arch/cm3.h>
- #include <arch/cm3/timer.h>
- #include <arch/cm3/stm/stm32_clk.h>
- #include <cfg/clock.h>
- #if defined(MCU_STM32F1)
- #include <arch/cm3/stm/vendor/stm32f10x.h>
- #else
- #warning "Unknown STM32 family"
- #endif
- /* Prepare some defaults if configuration is incomplete */
- #if !defined(SYSCLK_SOURCE)
- #define SYSCLK_SOURCE SYSCLK_HSI
- #endif
- static uint32_t SystemCoreClock = 0;
- static const uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
- static const uint8_t APBPrescTable[8] = {1, 1, 1, 1, 2, 4, 8, 16};
- /*---------------- Clock Setup Procedure ------------------------------
- *
- * Clock system ist arranged like this:
- *
- * ,--------------------------- USB
- * | ,--------------- CPU
- * | +--------------- SDIO
- * 4-16/25MHz HSE -+---PLLMUL-+-AHBPRES---+-- APB1PRESC--- APB1
- * | | +-- ABP2PRESC--- ABP2
- * 8MHz HSI -------+----------' '-- ADCPRESC---- ADC
- *
- *
- * ***** Setup of system clock configuration *****
- *
- * 1) Select system clock sources
- *
- * To setup system to use HSI call: SetSysClockSource( SYSCLK_HSI);
- * To setup system to use HSE call: SetSysClockSource( SYSCLK_HSE);
- *
- * To setup system to use the PLL output, first setup the PLL source:
- * SetPllClockSource( PLLCLK_HSI);
- * or
- * SetPllClockSource( PLLCLK_HSE);
- * Then call SetSysClockSource( SYSCLK_PLL);
- *
- * 2) Configure prescalers
- * After selecting the right clock sources, the prescalers need to
- * be configured:
- * Call SetSysClock(); to do this automatically.
- *
- */
- /*!
- * \brief Update SystemCoreClock according to Clock Register Values
- *
- * This function reads out the CPUs clock and PLL registers and assembles
- * the actual clock speed values into the SystemCoreClock local variable.
- */
- static void SystemCoreClockUpdate(void)
- {
- uint32_t tmp = 0, pllmull = 0, pllsource = 0;
- #ifdef STM32F10X_CL
- uint32_t prediv1source = 0, prediv1factor = 0, prediv2factor = 0, pll2mull = 0;
- #endif /* STM32F10X_CL */
- #if defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL)
- uint32_t prediv1factor = 0;
- #endif /* STM32F10X_LD_VL or STM32F10X_MD_VL */
- /* Get SYSCLK source -------------------------------------------------------*/
- tmp = RCC->CFGR & RCC_CFGR_SWS;
- switch (tmp)
- {
- case 0x00: /* HSI used as system clock */
- SystemCoreClock = HSI_VALUE;
- break;
- case 0x04: /* HSE used as system clock */
- SystemCoreClock = HSE_VALUE;
- break;
- case 0x08: /* PLL used as system clock */
- /* Get PLL clock source and multiplication factor ----------------------*/
- pllmull = RCC->CFGR & RCC_CFGR_PLLMULL;
- pllsource = RCC->CFGR & RCC_CFGR_PLLSRC;
- #ifndef STM32F10X_CL
- pllmull = ( pllmull >> 18) + 2;
- if (pllsource == 0x00) {
- /* HSI oscillator clock divided by 2 selected as PLL clock entry */
- SystemCoreClock = (HSI_VALUE >> 1) * pllmull;
- }
- else {
- #if defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL)
- prediv1factor = (RCC->CFGR2 & RCC_CFGR2_PREDIV1) + 1;
- /* HSE oscillator clock selected as PREDIV1 clock entry */
- SystemCoreClock = (HSE_VALUE / prediv1factor) * pllmull;
- #else
- /* HSE selected as PLL clock entry */
- if ((RCC->CFGR & RCC_CFGR_PLLXTPRE) != (uint32_t)RESET) {
- /* HSE oscillator clock divided by 2 */
- SystemCoreClock = (HSE_VALUE >> 1) * pllmull;
- }
- else {
- SystemCoreClock = HSE_VALUE * pllmull;
- }
- #endif
- }
- #else
- pllmull = pllmull >> 18;
- if (pllmull != 0x0D) {
- pllmull += 2;
- }
- else {
- /* PLL multiplication factor = PLL input clock * 6.5 */
- pllmull = 13 / 2;
- }
- if (pllsource == 0x00) {
- /* HSI oscillator clock divided by 2 selected as PLL clock entry */
- SystemCoreClock = (HSI_VALUE >> 1) * pllmull;
- }
- else {
- /* PREDIV1 selected as PLL clock entry */
- /* Get PREDIV1 clock source and division factor */
- prediv1source = RCC->CFGR2 & RCC_CFGR2_PREDIV1SRC;
- prediv1factor = (RCC->CFGR2 & RCC_CFGR2_PREDIV1) + 1;
- if (prediv1source == 0) {
- /* HSE oscillator clock selected as PREDIV1 clock entry */
- SystemCoreClock = (HSE_VALUE / prediv1factor) * pllmull;
- }
- else {
- /* PLL2 clock selected as PREDIV1 clock entry */
- /* Get PREDIV2 division factor and PLL2 multiplication factor */
- prediv2factor = ((RCC->CFGR2 & RCC_CFGR2_PREDIV2) >> 4) + 1;
- pll2mull = ((RCC->CFGR2 & RCC_CFGR2_PLL2MUL) >> 8 ) + 2;
- SystemCoreClock = (((HSE_VALUE / prediv2factor) * pll2mull) / prediv1factor) * pllmull;
- }
- }
- #endif /* STM32F10X_CL */
- break;
- default:
- SystemCoreClock = HSI_VALUE;
- break;
- }
- /* Compute HCLK clock frequency ----------------*/
- /* Get HCLK prescaler */
- tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)];
- /* HCLK clock frequency */
- SystemCoreClock >>= tmp;
- }
- /*!
- * \brief Control HSE clock.
- *
- * \param ena 0 disable clock, any other value enable it.
- * \return 0 on success, -1 on HSE start failed.
- */
- int CtlHseClock( uint8_t ena)
- {
- int rc = 0;
- uint32_t tout = HSE_STARTUP_TIMEOUT;
- volatile uint32_t HSEStatus = 0;
- if( ena) {
- /* Enable HSE clock */
- RCC->CR |= ((uint32_t)RCC_CR_HSEON);
- /* Wait till HSE is ready or time out is reached */
- do {
- HSEStatus = RCC->CR & RCC_CR_HSERDY;
- tout--;
- } while((HSEStatus == 0) && (tout > 0));
- if ((RCC->CR & RCC_CR_HSERDY) == RESET) {
- /* HSE failed to start */
- rc = -1;
- }
- }
- else {
- /* Disable HSE clock */
- RCC->CR &= ~RCC_CR_HSION;
- }
- return rc;
- }
- /*!
- * \brief Control HSI clock.
- *
- * \param ena 0 disable clock, any other value enable it.
- * \return 0 on success, -1 on HSI start failed.
- */
- int CtlHsiClock( uint8_t ena)
- {
- int rc = 0;
- uint32_t tout = HSE_STARTUP_TIMEOUT;
- volatile uint32_t HSIStatus = 0;
- if( ena) {
- /* Enable HSE clock */
- RCC->CR |= ((uint32_t)RCC_CR_HSION);
- /* Wait till HSE is ready or time out is reached */
- do {
- HSIStatus = RCC->CR & RCC_CR_HSIRDY;
- tout--;
- } while((HSIStatus == 0) && (tout > 0));
- if ((RCC->CR & RCC_CR_HSIRDY) == RESET) {
- /* HSE failed to start */
- rc = -1;
- }
- }
- else {
- /* Disable HSI clock */
- RCC->CR &= ~RCC_CR_HSION;
- }
- return rc;
- }
- /*!
- * \brief Control PLL clock.
- *
- * \param ena 0 disable clock, any other value enable it.
- * \return 0 on success, -1 on PLL start failed.
- */
- int CtlPllClock( uint8_t ena)
- {
- int rc = 0;
- uint32_t tout = HSE_STARTUP_TIMEOUT;
- volatile uint32_t PLLStatus = 0;
- if( ena) {
- /* Enable PLL */
- RCC->CR |= RCC_CR_PLLON;
- /* Wait till PLL is ready or time out is reached */
- do {
- PLLStatus = RCC->CR & RCC_CR_PLLRDY;
- tout--;
- } while((PLLStatus == 0) && (tout > 0));
- if ((RCC->CR & RCC_CR_PLLRDY) == RESET) {
- /* HSE failed to start */
- rc = -1;
- }
- }
- else {
- /* Disable HSE clock */
- RCC->CR &= ~RCC_CR_PLLON;
- }
- return rc;
- }
- /*!
- * \brief Configures the System clock source: HSE or HSI.
- * \note This function should be used only after reset.
- * \param src is one of PLLCLK_HSE, PLLCLK_HSI.
- * \return 0 if clock is running ale -1.
- */
- int SetPllClockSource( int src)
- {
- int rc = -1;
- if (src == PLLCLK_HSE) {
- rc = CtlHseClock(ENABLE);
- if (rc==0) {
- /* Select HSE/2 as PLL clock source */
- RCC->CFGR |= RCC_CFGR_PLLSRC|RCC_CFGR_PLLXTPRE;
- }
- }
- else if (src == PLLCLK_HSI) {
- rc = CtlHsiClock(ENABLE);
- /* Select HSI/2 as PLL clock source */
- RCC->CFGR &= ~(RCC_CFGR_PLLSRC|RCC_CFGR_PLLXTPRE);
- }
- return rc;
- }
- /*!
- * \brief Configures the System clock source: HSI, HS or PLL.
- * \note This function should be used only after reset.
- * \param src is one of SYSCLK_HSE, SYSCLK_HSI or SYSCLK_PLL.
- * \return 0 if selected clock is running else -1.
- */
- int SetSysClockSource( int src)
- {
- int rc = -1;
- if (src == SYSCLK_HSE) {
- rc = CtlHseClock(ENABLE);
- if (rc == 0) {
- /* Select HSE as system clock source */
- RCC->CFGR &= ~RCC_CFGR_SW;
- RCC->CFGR |= RCC_CFGR_SW_HSE;
- /* Wait till HSE is used as system clock source */
- while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSE);
- }
- }
- else if (src == SYSCLK_HSI) {
- rc = CtlHsiClock(ENABLE);
- if (rc == 0) {
- /* Select HSI as system clock source */
- RCC->CFGR &= ~RCC_CFGR_SW;
- RCC->CFGR |= RCC_CFGR_SW_HSI;
- /* Wait till HSI is used as system clock source */
- while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI);
- }
- }
- else if (src == SYSCLK_PLL) {
- rc = CtlPllClock(ENABLE);
- if (rc == 0) {
- /* Select HSI as system clock source */
- RCC->CFGR &= ~RCC_CFGR_SW;
- RCC->CFGR |= RCC_CFGR_SW_PLL;
- /* Wait till PLL is used as system clock source */
- while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL);
- }
- }
- /* Update core clock information */
- SystemCoreClockUpdate();
- return rc;
- }
- #if (SYSCLK_SOURCE == SYSCLK_HSI) || (SYSCLK_SOURCE == SYSCLK_HSE)
- /*!
- * \brief Configures the System clock coming from HSE or HSI oscillator.
- *
- * Enable HSI/HSE clock and setup HCLK, PCLK2 and PCLK1 prescalers.
- *
- * \param None.
- * \return 0 on success, -1 on fault of HSE.
- */
- int SetSysClock(void)
- {
- int rc = 0;
- register uint32_t cfgr;
- #if !defined(STM32F10X_LD_VL) && !defined(STM32F10X_MD_VL)
- /* Enable Prefetch Buffer */
- FLASH->ACR |= FLASH_ACR_PRFTBE;
- /* Flash 0 wait state */
- FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
- #if (SYSCLK_SOURCE == SYSCLK_HSE)
- if (HSE_VALUE > 24000000) {
- FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_1;
- }
- #endif
- #endif
- cfgr = RCC->CFGR;
- cfgr &= ~(RCC_CFGR_HPRE|RCC_CFGR_PPRE1|RCC_CFGR_PPRE2);
- /* HCLK = SYSCLK */
- cfgr |= (uint32_t)RCC_CFGR_HPRE_DIV1;
- /* PCLK2 = HCLK */
- cfgr |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
- /* PCLK1 = HCLK */
- cfgr |= (uint32_t)RCC_CFGR_PPRE1_DIV1;
- RCC->CFGR = cfgr;
- rc = SetSysClockSource(SYSCLK_SOURCE);
- return rc;
- }
- #else /* (SYSCLK_SOURCE == SYSCLK_HSI) || (SYSCLK_SOURCE == SYSCLK_HSE) */
- #if (PLLCLK_SOURCE==PLLCLK_HSE)
- #define PLLCLK_IN HSE_VALUE
- #else
- #define PLLCLK_IN (HSI_VALUE/2)
- #endif
- /**
- * @brief Sets System clock frequency to 72MHz and configure HCLK, PCLK2
- * and PCLK1 prescalers.
- * @note This function should be used only after reset.
- * @param None
- * @retval None
- */
- int SetSysClock(void)
- {
- int rc = 0;
- uint32_t Multiplier = SYSCLK_FREQ / (PLLCLK_IN>>1);
- uint32_t DividerX2 = RCC_CFGR_PLLXTPRE;
- uint32_t FlashWs = 0;
- /* If half of HSE_VALUE is to small for reaching target frequency
- * deactivate /2 divider. */
- if (Multiplier > 16) {
- DividerX2 = 0;
- Multiplier = SYSCLK_FREQ / PLLCLK_IN;
- }
- /* Check Limits */
- if (DividerX2) {
- if (((PLLCLK_IN>>1)*Multiplier) > 72000000UL) Multiplier--;
- }
- else {
- if ((PLLCLK_IN*Multiplier) > 72000000UL) Multiplier--;
- }
- /* Shift multiplier to corresponding RCC_CFGR register bits */
- Multiplier = ((Multiplier-2)&0xF)<<18;
- /* Enable PLL clock source */
- rc = SetPllClockSource(PLLCLK_SOURCE);
- if (rc) {
- /* Something went wrong with the PLL startup! */
- SetSysClockSource(SYSCLK_HSI);
- return rc;
- }
- /* Enable Prefetch Buffer */
- FLASH->ACR |= FLASH_ACR_PRFTBE;
- /* Flash wait state calculation and setup */
- if( SYSCLK_FREQ > 24000000)
- FlashWs++;
- if( SYSCLK_FREQ > 48000000)
- FlashWs++;
- FLASH->ACR &= ~FLASH_ACR_LATENCY;
- FLASH->ACR |= FlashWs;
- /* HCLK = SYSCLK */
- RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
- /* PCLK2 = HCLK */
- RCC->CFGR |= RCC_CFGR_PPRE2_DIV1;
- if( SYSCLK_FREQ > 36000000)
- /* PCLK1 = HCLK/2 */
- RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;
- else
- /* PCLK1 = HCLK */
- RCC->CFGR |= RCC_CFGR_PPRE1_DIV1;
- #ifdef STM32F10X_CL
- /* PLL configuration for Conetctivity Line Devices */
- /* Configure PLLs ------------------------------------------------------*/
- /* PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz */
- /* PREDIV1 configuration: PREDIV1CLK = PLL2 / 5 = 8 MHz */
- RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL |
- RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC);
- RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |
- RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5);
- /* Enable PLL2 */
- RCC->CR |= RCC_CR_PLL2ON;
- /* Wait till PLL2 is ready */
- while((RCC->CR & RCC_CR_PLL2RDY) == 0);
- /* PLL configuration: PLLCLK = PREDIV1 * 9 = 72 MHz */
- RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL);
- // TODO: Calculate online
- RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 |
- RCC_CFGR_PLLMULL9);
- #elif defined(STM32F10X_MD_VL) || defined (STM32F10X_LD_VL)
- /* PLL configuration for other devices */
- RCC->CFGR &= (uint32_t)(~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));
- RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_PREDIV1 | Multiplier | DividerX2);
- #else
- /* PLL configuration for other devices */
- RCC->CFGR &= (uint32_t)(~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));
- RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | Multiplier | DividerX2);
- #endif /* STM32F10X_CL */
- /* Start PLL, wait ready and switch to it as clock source */
- rc = SetSysClockSource(SYSCLK_SOURCE);
- if (rc) {
- /* Something went wrong with the PLL startup! */
- SetSysClockSource(SYSCLK_HSI);
- return rc;
- }
- return rc;
- }
- #endif /* (SYSCLK_SOURCE == SYSCLK_HSI) || (SYSCLK_SOURCE == SYSCLK_HSE) */
- /**
- * @brief requests System clock frequency
- *
- * @note This function should be used only after reset.
- * @param None
- * @retval None
- */
- uint32_t SysCtlClockGet(void)
- {
- SystemCoreClockUpdate();
- return SystemCoreClock;
- }
- /**
- * @brief requests frequency of the given clock
- *
- * @param idx NUT_HWCLK Index
- * @retval clock or 0 if idx points to an invalid clock
- */
- uint32_t STM_ClockGet(int idx)
- {
- SystemCoreClockUpdate();
- switch(idx) {
- case NUT_HWCLK_CPU:
- return SystemCoreClock;
- break;
- case NUT_HWCLK_PCLK1: {
- uint32_t tmp = (RCC->CFGR & RCC_CFGR_PPRE1) >> _BI32( RCC_CFGR_PPRE1_0);
- return SystemCoreClock/APBPrescTable[tmp];
- break;
- }
- case NUT_HWCLK_PCLK2: {
- uint32_t tmp = (RCC->CFGR & RCC_CFGR_PPRE2) >> _BI32( RCC_CFGR_PPRE2_0);
- return SystemCoreClock/APBPrescTable[tmp];
- break;
- }
- default:
- return 0;
- break;
- }
- }
|