| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508 |
- /*
- * Copyright (C) 2012 by Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
- *
- * 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/
- */
- #include <cfg/arch.h>
- #include <arch/cm3.h>
- #include <arch/cm3/timer.h>
- #include <arch/cm3/stm/stm32_clk.h>
- #include <cfg/clock.h>
- #include <arch/cm3/stm/stm32xxxx.h>
- #if !defined(HSI_VALUE)
- #define HSI_VALUE 160000000
- #endif /* HSI_VALUE */
- #if !defined(HSE_STARTUP_TIMEOUT)
- #define HSE_STARTUP_TIMEOUT ((uint32_t)5000) /*!< Time out for HSE start up, in ms */
- #endif
- static uint32_t SystemCoreClock = 0;
- /* Prepare some defaults if configuration is incomplete */
- #if !defined(SYSCLK_SOURCE)
- #define SYSCLK_SOURCE SYSCLK_HSI
- #endif
- 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:
- *
- * /Q------------------------------ USB
- * | ,--------------- CPU
- * | +--------------- SDIO
- * 4-26 MHz HSE -+--/M*N/P--+-AHBPRES---+-- APB1PRESC--- APB1
- * | | +-- ABP2PRESC--- ABP2
- * 16MHz 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)
- {
- RCC_TypeDef *rcc = (RCC_TypeDef *)RCC_BASE;
- uint32_t tmp = 0;
- uint32_t cfgr;
- uint32_t hpre;
- /* Get SYSCLK source ---------------------------------------------------*/
- cfgr = RCC->CFGR & RCC_CFGR_SWS;
- switch (cfgr) {
- case RCC_CFGR_SWS_HSE:
- tmp = HSE_VALUE;
- break;
- case RCC_CFGR_SWS_PLL: {
- uint32_t pllcfgr = rcc->PLLCFGR;
- uint32_t n = (pllcfgr & RCC_PLLCFGR_PLLN) >> _BI32(RCC_PLLCFGR_PLLN_0);
- uint32_t m = (pllcfgr & RCC_PLLCFGR_PLLM) >> _BI32(RCC_PLLCFGR_PLLM_0);
- uint32_t p = (pllcfgr & RCC_PLLCFGR_PLLP) >> _BI32(RCC_PLLCFGR_PLLP_0);
- /* Pll Divisor is (p + 1) * 2. Move * 2 into the base clock sonstant*/
- if ((pllcfgr & RCC_PLLCFGR_PLLSRC_HSE) == RCC_PLLCFGR_PLLSRC_HSE)
- tmp = HSE_VALUE / 2;
- else
- tmp = HSI_VALUE / 2;
- tmp = ((tmp / m) * n)/(p + 1);
- break;
- }
- default:
- tmp = HSI_VALUE;
- }
- hpre = (cfgr & RCC_CFGR_HPRE) >> _BI32(RCC_CFGR_HPRE_0);
- SystemCoreClock = tmp >> AHBPrescTable[hpre];
- }
- /* Functional same as F1 */
- /*!
- * \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 */
- RCC->CR |= RCC_CR_HSEON;
- /* Wait till HSE is ready or time out is reached */
- do {
- tout--;
- HSEStatus = RCC->CR & RCC_CR_HSERDY;
- } while((HSEStatus == 0) && (tout > 0));
- if ((RCC->CR & RCC_CR_HSERDY) == 0) {
- /* HSE failed to start */
- rc = -1;
- }
- }
- else {
- /* Disable HSE clock */
- RCC->CR &= ~RCC_CR_HSEON;
- }
- return rc;
- }
- /* Functional same as F1 */
- /*!
- * \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 HSI */
- RCC->CR |= RCC_CR_HSION;
- /* Wait till HSI is ready or time out is reached */
- do {
- tout--;
- HSIStatus = RCC->CR & RCC_CR_HSIRDY;
- } while((HSIStatus == 0) && (tout > 0));
- if ((RCC->CR & RCC_CR_HSIRDY) == 0) {
- /* HSI failed to start */
- rc = -1;
- }
- }
- else {
- /* Disable HSE clock */
- RCC->CR &= ~RCC_CR_HSION;
- }
- return rc;
- }
- /* Functional same as F1 */
- /*!
- * \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 {
- tout--;
- PLLStatus = RCC->CR & RCC_CR_PLLRDY;
- } while((PLLStatus == 0) && (tout > 0));
- if ((RCC->CR & RCC_CR_PLLRDY) == 0) {
- /* PLL 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 with PLL disables
- * \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(1);
- if (rc==0) {
- CM3BBSET(RCC_BASE, RCC_TypeDef, PLLCFGR, _BI32(RCC_PLLCFGR_PLLSRC));
- }
- }
- else if (src == PLLCLK_HSI) {
- rc = CtlHsiClock(1);
- /* Select HSI/2 as PLL clock source */
- if (rc==0) {
- CM3BBCLR(RCC_BASE, RCC_TypeDef, PLLCFGR, _BI32(RCC_PLLCFGR_PLLSRC));
- }
- }
- 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(1);
- 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(1);
- 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(1);
- 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;
- /* Todo: Check Voltage range! Here 2.7-3.6 Volt is assumed */
- /* For 2.7-3.6 Volt up to 30 MHz no Wait state required */
- 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
- #endif
- /**
- * @brief Sets System clock frequency to 120/168MHz and configure HCLK, PCLK2
- * and PCLK1 prescalers.
- * @note This function should be used only after reset.
- * @param None
- * @retval None
- */
- /*
- Ranges :
- M: 2..63
- N: 64.. 432
- P: 2, 4, 6, 8
- Q: 2..15
- 0.95 MHz < PLLCLK_IN/M < 2 MHz, Prefer 2 MHz for low jitter
- 192 MHz < PLLCLK_IN/M*N < 432 MHz
- PLLCLK_IN/M*N/P < 168 MHz
- PLLCLK_IN/M*N/Q < 48 MHz, Use 48 MHz for USB
- Easy Approach:
- Try to reach fvco = 336 Mhz with M/N.
- Require a clock >= 4 MHz in 2 MHz Steps
- */
- int SetSysClock(void)
- {
- int rc = 0;
- uint32_t rcc_reg;
- #if !defined(STM32_VRANGE) || STM32_VRANGE == 0
- #define FLASH_BASE_FREQ 30000000
- #elif STM32_VRANGE == 1
- #define FLASH_BASE_FREQ 24000000
- #elif STM32_VRANGE == 2
- #define FLASH_BASE_FREQ 22000000
- #elif STM32_VRANGE == 3
- #define FLASH_BASE_FREQ 20000000
- #endif
- #if PLLCLK_IN > 26000000
- #warning PLL Input frequency too high
- #endif
- #if (PLLCLK_IN > 3999999) && ((PLLCLK_IN % 2000000L) == 0)
- #define PLLM (PLLCLK_IN/2000000)
- #define PLLN ((SYSCLK_FREQ/1000000) << _BI32(RCC_PLLCFGR_PLLN_0))
- #elif (PLLCLK_IN > 1999999) && ((PLLCLK_IN % 1000000L) == 0)
- #define PLLM (PLLCLK_IN/1000000)
- #define PLLN ((SYSCLK_FREQ/500000 ) << _BI32(RCC_PLLCFGR_PLLN_0))
- #else
- #warning "PLL Source frequency isn't a multiple of 1 or 2 MHz"
- #endif
- #define PLLP ((2/2-1) << _BI32(RCC_PLLCFGR_PLLP_0))
- #define PLLQ (5 << _BI32(RCC_PLLCFGR_PLLQ_0))
- #define NUT_FLASH_LATENCY (SYSCLK_FREQ/FLASH_BASE_FREQ)
- /* Select System frequency up to 168 MHz */
- RCC->APB1ENR |= RCC_APB1ENR_PWREN;
- rcc_reg = RCC->PLLCFGR;
- rcc_reg &= ~(RCC_PLLCFGR_PLLM | RCC_PLLCFGR_PLLN | RCC_PLLCFGR_PLLP | RCC_PLLCFGR_PLLQ);
- #if (PLLCLK_SOURCE==PLLCLK_HSE)
- if (CtlHseClock(1) != 0)
- return -1;
- rcc_reg = PLLM | PLLN | PLLP | PLLQ | RCC_PLLCFGR_PLLSRC_HSE;
- #else
- if (CtlHsiClock(1) != 0)
- return -1;
- rcc_reg = PLLM| PLLN | PLLP | PLLQ | RCC_PLLCFGR_PLLSRC_HSI;
- #endif
- RCC->PLLCFGR = rcc_reg;
- rcc_reg = FLASH->ACR;
- rcc_reg &= ~FLASH_ACR_LATENCY;
- #if STM32_VRANGE == 3
- /* Prefetch must be off*/
- rcc_reg |= NUT_FLASH_LATENCY;
- #else
- rcc_reg |= NUT_FLASH_LATENCY | FLASH_ACR_PRFTEN ;
- #endif
- /* Enable Instruction and Data cache */
- rcc_reg |= FLASH_ACR_ICEN | FLASH_ACR_DCEN;
- FLASH->ACR = rcc_reg;
- rcc_reg = RCC->CFGR;
- rcc_reg &= ~(RCC_CFGR_HPRE | RCC_CFGR_PPRE2| RCC_CFGR_PPRE1);
- /* HCLK = SYSCLK, PCLK2 = HCLK/2 , PCLK1 = HCLK/4 */
- rcc_reg |= (RCC_CFGR_HPRE_DIV1 | RCC_CFGR_PPRE2_DIV2| RCC_CFGR_PPRE1_DIV4);
- RCC->CFGR = rcc_reg;
- /* 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;
- }
- }
|