1006 lines
29 KiB
C
1006 lines
29 KiB
C
/****************************************************************************
|
|
* arch/arm/src/stm32/stm32g4xxxx_rcc.c
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
* this work for additional information regarding copyright ownership. The
|
|
* ASF licenses this file to you 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.
|
|
*
|
|
****************************************************************************/
|
|
|
|
/* Unless otherwise specified, when comments in this file refer to the
|
|
* reference manual, that is the STM32G4 Reference Manual (RM0440 Rev 5).
|
|
*
|
|
* This file requires a clocking configuration, which is set in board.h,
|
|
* consisting of some or all of the following defines:
|
|
*
|
|
* STM32_HSI_FREQUENCY should be defined to the frequency of the MCU's
|
|
* high speed internal (HSI) oscillator in Hz.
|
|
*
|
|
* STM32_LSI_FREQUENCY should be defined to the frequency of the MCU's low
|
|
* speed internal (LSI) oscillator in Hz.
|
|
*
|
|
* If the board has an external crystal or oscillator, STM32_BOARD_XTAL
|
|
* should be defined its frequency in Hz.
|
|
*
|
|
* If the board has a high speed external (HSE) crystal/oscillator,
|
|
* STM32_HSE_FREQUENCY should be defined to its frequency in Hz.
|
|
*
|
|
* If the board has a low speed external (LSE) crystal/oscillator,
|
|
* STM32_LSE_FREQUENCY should be defined to its frequency in Hz.
|
|
*
|
|
* If the PLL is used, its source must be set by defining
|
|
* STM32_PLLCFGR_PLLSRC to one of the following: RCC_PLLCFGR_PLLSRC_HSI or
|
|
* RCC_PLLCFGR_PLLSRC_HSE, and each of its output clock(s) should be
|
|
* enabled, as needed, by setting STM32_PLLCFGR_PLLCFG to the bitwise OR
|
|
* of RCC_PLLCFGR_PLLPEN, RCC_PLLCFGR_PLLQEN, and/or RCC_PLLCFGR_PLLREN.
|
|
* Its prescale division and VCO multiplication factors must be set by
|
|
* defining STM32_PLLCFGR_PLLM and STM32_PLLCFGR_PLLN, using the
|
|
* RCC_PLLCFGR_PLLM() and RCC_PLLCFGR_PLLN() macros, respectively. The
|
|
* division factors for each enabled PLL output must be set by defining
|
|
* STM32_PLLCFGR_PLLP, STM32_PLLCFGR_PLLQ, and STM32_PLLCFGR_PLLR, using
|
|
* the RCC_PLLCFGR_PLLP(), RCC_PLLCFGR_PLLQ(), and RCC_PLLCFGR_PLLR()
|
|
* macros, respectively. The resulting frequencies must be specified by
|
|
* defining STM32_VCO_FREQUENCY, STM32_PLLP_FREQUENCY,
|
|
* STM32_PLLQ_FREQUENCY, and STM32_PLLR_FREQUENCY to those frequency in
|
|
* Hz, which can be calculated in terms of above-defined frequencies.
|
|
*
|
|
* The SYSCLK source must be given by defining STM32_SYSCLK_SW to one of
|
|
* RCC_CFGR_SW_HSI, RCC_CFGR_SW_HSE, or RCC_CFGR_SW_PLL, defining
|
|
* STM32_SYSCLK_SWS to one of RCC_CFGR_SWS_HSI, RCC_CFGR_SWS_HSE, or
|
|
* RCC_CFGR_SWS_PLL, and defining STM32_SYSCLK_FREQUENCY to the resulting
|
|
* SYSCLK frequency in Hz. For example, if SYSCLK is driven by the PLL "R"
|
|
* clock, STM32_SYSCLK_FREQUENCY can be defined to STM32_PLLR_FREQUENCY,
|
|
* which was defined earlier.
|
|
*
|
|
* The AHB clock (HCLK) must be setup by defining STM32_RCC_CFGR_HPRE to
|
|
* one of RCC_CFGR_HPRE_SYSCLK, RCC_CFGR_HPRE_SYSCLKd2,
|
|
* RCC_CFGR_HPRE_SYSCLKd4, RCC_CFGR_HPRE_SYSCLKd8,
|
|
* RCC_CFGR_HPRE_SYSCLKd16, RCC_CFGR_HPRE_SYSCLKd64,
|
|
* RCC_CFGR_HPRE_SYSCLKd128, RCC_CFGR_HPRE_SYSCLKd256, or
|
|
* RCC_CFGR_HPRE_SYSCLKd512. Also, STM32_HCLK_FREQUENCY must be defined to
|
|
* its resulting frequency in Hz. For example, if HCLK is driven by
|
|
* SYSCLK, STM32_HCLK_FREQUENCY can be defined to STM32_SYSCLK_FREQUENCY.
|
|
*
|
|
* The APB1 clock (PCLK1) must be setup by defining STM32_RCC_CFGR_PPRE1
|
|
* to one of RCC_CFGR_PPRE1_HCLK, RCC_CFGR_PPRE1_HCLKd2,
|
|
* RCC_CFGR_PPRE1_HCLKd4, RCC_CFGR_PPRE1_HCLKd8, RCC_CFGR_PPRE1_HCLKd16
|
|
* and defining STM32_PCLK1_FREQUENCY to its frequency in Hz.
|
|
*
|
|
* The APB2 clock (PCLK2) must be setup by defining STM32_RCC_CFGR_PPRE2
|
|
* to one of RCC_CFGR_PPRE2_HCLK, RCC_CFGR_PPRE2_HCLKd2,
|
|
* RCC_CFGR_PPRE2_HCLKd4, RCC_CFGR_PPRE2_HCLKd8, RCC_CFGR_PPRE2_HCLKd16
|
|
* and defining STM32_PCLK2_FREQUENCY to its frequency in Hz.
|
|
*/
|
|
|
|
/****************************************************************************
|
|
* Included Files
|
|
****************************************************************************/
|
|
|
|
#include <nuttx/config.h>
|
|
|
|
#include "hardware/stm32g4xxxx_pwr.h"
|
|
|
|
/****************************************************************************
|
|
* Pre-processor Definitions
|
|
****************************************************************************/
|
|
|
|
#if (STM32_SYSCLK_SW == RCC_CFGR_SW_HSE)
|
|
# define USE_HSE
|
|
#endif
|
|
|
|
#if (STM32_SYSCLK_SW == RCC_CFGR_SW_HSI)
|
|
# define USE_HSI
|
|
#endif
|
|
|
|
#if (STM32_SYSCLK_SW == RCC_CFGR_SW_PLL)
|
|
# define USE_PLL
|
|
# define PLLRDY_TIMEOUT (100 * CONFIG_BOARD_LOOPSPERMSEC)
|
|
# if (STM32_PLLCFGR_PLLSRC == RCC_PLLCFGR_PLLSRC_HSE)
|
|
# define USE_HSE
|
|
# elif (STM32_PLLCFGR_PLLSRC == RCC_PLLCFGR_PLLSRC_HSI)
|
|
# define USE_HSI
|
|
# else
|
|
# error "STM32_SYSCLK_SW is RCC_CFGR_SW_PLL but STM32_PLLCFGR_PLLSRC is not recognized!"
|
|
# endif
|
|
#endif
|
|
|
|
#if defined(USE_HSI)
|
|
# define HSIRDY_TIMEOUT (100 * CONFIG_BOARD_LOOPSPERMSEC)
|
|
#endif
|
|
|
|
#if defined(USE_HSE)
|
|
# define HSERDY_TIMEOUT (100 * CONFIG_BOARD_LOOPSPERMSEC)
|
|
#endif
|
|
|
|
/* Per the reference manual:
|
|
*
|
|
* Choose PWR VOS range setting and R1MODE based on SYSCLK frequency (see
|
|
* section 6.1.5, Dynamic voltage scaling management).
|
|
*
|
|
* Choose number of FLASH wait states according to CPU clock (HCLK)
|
|
* frequency (see section 3.3.3, Read access latency, and Table 9 in that
|
|
* section.
|
|
*
|
|
* This will define FLASH_ACR_LATENCY_SETTING, PWR_CR1_VOS_RANGE_SETTING,
|
|
* and PWR_CR5_R1MODE_SETTING to the appropriate settings.
|
|
*/
|
|
|
|
#if (STM32_SYSCLK_FREQUENCY > 26000000)
|
|
# define PWR_CR1_VOS_RANGE_SETTING PWR_CR1_VOS_RANGE_1
|
|
# if (STM32_SYSCLK_FREQUENCY > 150000000) /* Table 9, left column, "Vcore Range 1 boost mode" */
|
|
# define PWR_CR5_R1MODE_SETTING 0
|
|
# if (STM32_HCLK_FREQUENCY <= 34000000)
|
|
# define FLASH_ACR_LATENCY_SETTING FLASH_ACR_LATENCY_0
|
|
# elif (STM32_HCLK_FREQUENCY <= 68000000)
|
|
# define FLASH_ACR_LATENCY_SETTING FLASH_ACR_LATENCY_1
|
|
# elif (STM32_HCLK_FREQUENCY <= 102000000)
|
|
# define FLASH_ACR_LATENCY_SETTING FLASH_ACR_LATENCY_2
|
|
# elif (STM32_HCLK_FREQUENCY <= 136000000)
|
|
# define FLASH_ACR_LATENCY_SETTING FLASH_ACR_LATENCY_3
|
|
# elif (STM32_HCLK_FREQUENCY <= 170000000)
|
|
# define FLASH_ACR_LATENCY_SETTING FLASH_ACR_LATENCY_4
|
|
# else
|
|
# error "Incorrect STM32_HCLK_FREQUENCY (Vcore range 1 boost mode)!"
|
|
# endif
|
|
# else /* Table 9, middle column, "Vcore Range 1 normal mode" */
|
|
# define PWR_CR5_R1MODE_SETTING PWR_CR5_R1MODE
|
|
# if (STM32_HCLK_FREQUENCY <= 30000000)
|
|
# define FLASH_ACR_LATENCY_SETTING FLASH_ACR_LATENCY_0
|
|
# elif (STM32_HCLK_FREQUENCY <= 60000000)
|
|
# define FLASH_ACR_LATENCY_SETTING FLASH_ACR_LATENCY_1
|
|
# elif (STM32_HCLK_FREQUENCY <= 90000000)
|
|
# define FLASH_ACR_LATENCY_SETTING FLASH_ACR_LATENCY_2
|
|
# elif (STM32_HCLK_FREQUENCY <= 120000000)
|
|
# define FLASH_ACR_LATENCY_SETTING FLASH_ACR_LATENCY_3
|
|
# elif (STM32_HCLK_FREQUENCY <= 150000000)
|
|
# define FLASH_ACR_LATENCY_SETTING FLASH_ACR_LATENCY_4
|
|
# else
|
|
# error "Incorrect STM32_HCLK_FREQUENCY (Vcore range 1 normal mode)!"
|
|
# endif
|
|
# endif
|
|
#else /* Table 9, right column, "Vcore Range 2" */
|
|
# define PWR_CR1_VOS_RANGE_SETTING PWR_CR1_VOS_RANGE_2;
|
|
# define PWR_CR5_R1MODE_SETTING 0
|
|
# if (STM32_HCLK_FREQUENCY <= 12000000)
|
|
# define FLASH_ACR_LATENCY_SETTING FLASH_ACR_LATENCY_0
|
|
# elif (STM32_HCLK_FREQUENCY <= 24000000)
|
|
# define FLASH_ACR_LATENCY_SETTING FLASH_ACR_LATENCY_1
|
|
# elif (STM32_HCLK_FREQUENCY <= 26000000)
|
|
# define FLASH_ACR_LATENCY_SETTING FLASH_ACR_LATENCY_2
|
|
# else
|
|
# error "Incorrect STM32_HCLK_FREQUENCY! (Vcore range 2)"
|
|
# endif
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Private Types
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Private Function Prototypes
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Private Data
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Public Data
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Private Functions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Name: rcc_reset
|
|
*
|
|
* Description:
|
|
* Put all RCC registers in reset state.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static inline void rcc_reset(void)
|
|
{
|
|
uint32_t regval;
|
|
|
|
/* Set HSION bit to the reset value and wait until HSI ready */
|
|
|
|
regval = getreg32(STM32_RCC_CR);
|
|
regval |= RCC_CR_HSION;
|
|
putreg32(regval, STM32_RCC_CR);
|
|
|
|
while ((getreg32(STM32_RCC_CR) & RCC_CR_HSIRDY) != RCC_CR_HSIRDY)
|
|
{
|
|
}
|
|
|
|
/* Reset HSI trimming */
|
|
|
|
regval = getreg32(STM32_RCC_ICSCR);
|
|
regval &= ~(RCC_ICSCR_HSITRIM_MASK);
|
|
regval |= RCC_ICSCR_HSITRIM_RESET;
|
|
putreg32(regval, STM32_RCC_ICSCR);
|
|
|
|
/* Reset CFGR register */
|
|
|
|
regval = getreg32(STM32_RCC_CFGR);
|
|
regval &= RCC_CFGR_RESERVED_MASK;
|
|
regval |= RCC_CFGR_RESET;
|
|
putreg32(regval, STM32_RCC_CFGR);
|
|
|
|
/* Wait until HSI is being used as the system clock, else we cannot clear
|
|
* the HSEON, HSEBYP, and PLLON bits.
|
|
*/
|
|
|
|
while ((getreg32(STM32_RCC_CFGR) & RCC_CFGR_SWS_MASK) != RCC_CFGR_SWS_HSI)
|
|
{
|
|
}
|
|
|
|
/* Clear the HSEON, HSEBYP, and PLLON bits */
|
|
|
|
regval = getreg32(STM32_RCC_CR);
|
|
regval &= ~(RCC_CR_HSEON | RCC_CR_HSEBYP | RCC_CR_PLLON);
|
|
putreg32(regval, STM32_RCC_CR);
|
|
|
|
/* Wait until PLL is OFF, else we cannot change some of the bits in the
|
|
* PLLCFGR register.
|
|
*/
|
|
|
|
while ((getreg32(STM32_RCC_CR) & RCC_CR_PLLRDY) != 0)
|
|
{
|
|
}
|
|
|
|
/* Reset PLLCFGR register */
|
|
|
|
regval = getreg32(STM32_RCC_PLLCFGR);
|
|
regval &= RCC_PLLCFGR_RESERVED_MASK;
|
|
regval |= RCC_PLLCFGR_RESET;
|
|
putreg32(RCC_PLLCFGR_RESET, STM32_RCC_PLLCFGR);
|
|
|
|
/* Disable all RCC interrupts and clear any previously pended ones */
|
|
|
|
putreg32(0, STM32_RCC_CIER);
|
|
putreg32(0xffffffff, STM32_RCC_CICR);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: rcc_enableahb1
|
|
*
|
|
* Description:
|
|
* Enable selected AHB1 peripherals.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static inline void rcc_enableahb1(void)
|
|
{
|
|
uint32_t regval;
|
|
|
|
regval = getreg32(STM32_RCC_AHB1ENR);
|
|
regval |= RCC_AHB1ENR_FLASHEN;
|
|
|
|
#if defined(CONFIG_STM32_DMA1)
|
|
regval |= RCC_AHB1ENR_DMA1EN;
|
|
#endif
|
|
|
|
#if defined(CONFIG_STM32_DMA2)
|
|
regval |= RCC_AHB1ENR_DMA2EN;
|
|
#endif
|
|
|
|
#if defined(CONFIG_STM32_DMA1) || defined(CONFIG_STM32_DMA2)
|
|
regval |= RCC_AHB1ENR_DMAMUX1EN;
|
|
#endif
|
|
|
|
#if defined(CONFIG_STM32_CORDIC)
|
|
regval |= RCC_AHB1ENR_CORDICEN;
|
|
#endif
|
|
|
|
#if defined(CONFIG_STM32_FMAC)
|
|
regval |= RCC_AHB1ENR_FMACEN;
|
|
#endif
|
|
|
|
#if defined(CONFIG_STM32_CRC)
|
|
regval |= RCC_AHB1ENR_CRCEN;
|
|
#endif
|
|
|
|
putreg32(regval, STM32_RCC_AHB1ENR);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: rcc_enableahb2
|
|
*
|
|
* Description:
|
|
* Enable selected AHB2 peripherals.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static inline void rcc_enableahb2(void)
|
|
{
|
|
uint32_t regval;
|
|
|
|
regval = getreg32(STM32_RCC_AHB2ENR);
|
|
|
|
#if (STM32_NGPIO_PORTS > 0)
|
|
regval |= (RCC_AHB2ENR_GPIOAEN
|
|
# if (STM32_NGPIO_PORTS > 1)
|
|
| RCC_AHB2ENR_GPIOBEN
|
|
# endif
|
|
# if (STM32_NGPIO_PORTS > 2)
|
|
| RCC_AHB2ENR_GPIOCEN
|
|
# endif
|
|
# if (STM32_NGPIO_PORTS > 3)
|
|
| RCC_AHB2ENR_GPIODEN
|
|
# endif
|
|
# if (STM32_NGPIO_PORTS > 4)
|
|
| RCC_AHB2ENR_GPIOEEN
|
|
# endif
|
|
# if (STM32_NGPIO_PORTS > 5)
|
|
| RCC_AHB2ENR_GPIOFEN
|
|
# endif
|
|
# if (STM32_NGPIO_PORTS > 6)
|
|
| RCC_AHB2ENR_GPIOGEN
|
|
# endif
|
|
);
|
|
#endif
|
|
|
|
#if defined(CONFIG_STM32_ADC1) || defined(CONFIG_STM32_ADC2)
|
|
regval |= RCC_AHB2ENR_ADC12EN;
|
|
#endif
|
|
|
|
#if defined(CONFIG_STM32_ADC3) || defined(CONFIG_STM32_ADC4) || \
|
|
defined(CONFIG_STM32_ADC5)
|
|
regval |= RCC_AHB2ENR_ADC345EN;
|
|
#endif
|
|
|
|
#if defined(CONFIG_STM32_DAC1)
|
|
regval |= RCC_AHB2ENR_DAC1EN;
|
|
#endif
|
|
|
|
#if defined(CONFIG_STM32_DAC2)
|
|
regval |= RCC_AHB2ENR_DAC2EN;
|
|
#endif
|
|
|
|
#if defined(CONFIG_STM32_DAC3)
|
|
regval |= RCC_AHB2ENR_DAC3EN;
|
|
#endif
|
|
|
|
#if defined(CONFIG_STM32_DAC4)
|
|
regval |= RCC_AHB2ENR_DAC4EN;
|
|
#endif
|
|
|
|
#if defined(CONFIG_STM32_RNG)
|
|
regval |= RCC_AHB2ENR_RNGEN;
|
|
#endif
|
|
|
|
putreg32(regval, STM32_RCC_AHB2ENR);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: rcc_enableahb3
|
|
*
|
|
* Description:
|
|
* Enable selected AHB3 peripherals.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static inline void rcc_enableahb3(void)
|
|
{
|
|
uint32_t regval;
|
|
|
|
regval = getreg32(STM32_RCC_AHB3ENR);
|
|
|
|
#if defined(CONFIG_STM32_FMC)
|
|
regval |= RCC_AHB3ENR_FMCEN;
|
|
#endif
|
|
|
|
#if defined(CONFIG_STM32_QSPI)
|
|
regval |= RCC_AHB3ENR_QSPIEN;
|
|
#endif
|
|
|
|
putreg32(regval, STM32_RCC_AHB3ENR);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: rcc_enableapb1
|
|
*
|
|
* Description:
|
|
* Enable selected APB1 peripherals.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static inline void rcc_enableapb1(void)
|
|
{
|
|
uint32_t regval;
|
|
|
|
/* Careful: There are two separate registers for enabling APB1
|
|
* peripherals. Configure the first register:
|
|
*/
|
|
|
|
regval = getreg32(STM32_RCC_APB1ENR1);
|
|
regval |= RCC_APB1ENR1_PWREN;
|
|
|
|
#if defined(CONFIG_STM32_TIM2)
|
|
regval |= RCC_APB1ENR1_TIM2EN;
|
|
#endif
|
|
|
|
#if defined(CONFIG_STM32_TIM3)
|
|
regval |= RCC_APB1ENR1_TIM3EN;
|
|
#endif
|
|
|
|
#if defined(CONFIG_STM32_TIM4)
|
|
regval |= RCC_APB1ENR1_TIM4EN;
|
|
#endif
|
|
|
|
#if defined(CONFIG_STM32_TIM5)
|
|
regval |= RCC_APB1ENR1_TIM5EN;
|
|
#endif
|
|
|
|
#if defined(CONFIG_STM32_TIM6)
|
|
regval |= RCC_APB1ENR1_TIM6EN;
|
|
#endif
|
|
|
|
#if defined(CONFIG_STM32_TIM7)
|
|
regval |= RCC_APB1ENR1_TIM7EN;
|
|
#endif
|
|
|
|
#if defined(CONFIG_STM32_CRS)
|
|
regval |= RCC_APB1ENR1_CRSEN;
|
|
#endif
|
|
|
|
#if defined(CONFIG_STM32_RTC)
|
|
regval |= RCC_APB1ENR1_RTCAPBEN;
|
|
#endif
|
|
|
|
#if defined(CONFIG_STM32_WWDG)
|
|
regval |= RCC_APB1ENR1_WWDGEN;
|
|
#endif
|
|
|
|
#if defined(CONFIG_STM32_SPI2)
|
|
regval |= RCC_APB1ENR1_SPI2EN;
|
|
#endif
|
|
|
|
#if defined(CONFIG_STM32_SPI3)
|
|
regval |= RCC_APB1ENR1_SPI3EN;
|
|
#endif
|
|
|
|
#if defined(CONFIG_STM32_USART2)
|
|
regval |= RCC_APB1ENR1_USART2EN;
|
|
#endif
|
|
|
|
#if defined(CONFIG_STM32_USART3)
|
|
regval |= RCC_APB1ENR1_USART3EN;
|
|
#endif
|
|
|
|
#if defined(CONFIG_STM32_UART4)
|
|
regval |= RCC_APB1ENR1_UART4EN;
|
|
#endif
|
|
|
|
#if defined(CONFIG_STM32_UART5)
|
|
regval |= RCC_APB1ENR1_UART5EN;
|
|
#endif
|
|
|
|
#if defined(CONFIG_STM32_I2C1)
|
|
regval |= RCC_APB1ENR1_I2C1EN;
|
|
#endif
|
|
|
|
#if defined(CONFIG_STM32_I2C2)
|
|
regval |= RCC_APB1ENR1_I2C2EN;
|
|
#endif
|
|
|
|
#if defined(CONFIG_STM32_USB) || defined(CONFIG_STM32_USBFS)
|
|
regval |= RCC_APB1ENR1_USBEN;
|
|
#endif
|
|
|
|
#if defined(CONFIG_STM32_FDCAN)
|
|
regval |= RCC_APB1ENR1_FDCANEN;
|
|
#endif
|
|
|
|
#if defined(CONFIG_STM32_I2C3)
|
|
regval |= RCC_APB1ENR1_I2C3EN;
|
|
#endif
|
|
|
|
#if defined(CONFIG_STM32_LPTIM1)
|
|
regval |= RCC_APB1ENR1_LPTIM1EN;
|
|
#endif
|
|
|
|
putreg32(regval, STM32_RCC_APB1ENR1);
|
|
|
|
/* Now configure the second register: */
|
|
|
|
regval = getreg32(STM32_RCC_APB1ENR2);
|
|
|
|
#if defined(CONFIG_STM32_LPUART1)
|
|
regval |= RCC_APB1ENR2_LPUART1EN;
|
|
#endif
|
|
|
|
#if defined(CONFIG_STM32_I2C4)
|
|
regval |= RCC_APB1ENR2_I2C4EN;
|
|
#endif
|
|
|
|
#if defined(CONFIG_STM32_UCPD)
|
|
regval |= RCC_APB1ENR2_UCPD1EN;
|
|
#endif
|
|
|
|
putreg32(regval, STM32_RCC_APB1ENR2);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: rcc_enableapb2
|
|
*
|
|
* Description:
|
|
* Enable selected APB2 peripherals.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static inline void rcc_enableapb2(void)
|
|
{
|
|
uint32_t regval;
|
|
|
|
regval = getreg32(STM32_RCC_APB2ENR);
|
|
|
|
#if defined(CONFIG_STM32_SYSCFG)
|
|
regval |= RCC_APB2ENR_SYSCFGEN;
|
|
#endif
|
|
|
|
#if defined(CONFIG_STM32_TIM1)
|
|
regval |= RCC_APB2ENR_TIM1EN;
|
|
#endif
|
|
|
|
#if defined(CONFIG_STM32_SPI1)
|
|
regval |= RCC_APB2ENR_SPI1EN;
|
|
#endif
|
|
|
|
#if defined(CONFIG_STM32_TIM8)
|
|
regval |= RCC_APB2ENR_TIM8EN;
|
|
#endif
|
|
|
|
#if defined(CONFIG_STM32_USART1)
|
|
regval |= RCC_APB2ENR_USART1EN;
|
|
#endif
|
|
|
|
#if defined(CONFIG_STM32_SPI4)
|
|
regval |= RCC_APB2ENR_SPI4EN;
|
|
#endif
|
|
|
|
#if defined(CONFIG_STM32_TIM15)
|
|
regval |= RCC_APB2ENR_TIM15EN;
|
|
#endif
|
|
|
|
#if defined(CONFIG_STM32_TIM16)
|
|
regval |= RCC_APB2ENR_TIM16EN;
|
|
#endif
|
|
|
|
#if defined(CONFIG_STM32_TIM17)
|
|
regval |= RCC_APB2ENR_TIM17EN;
|
|
#endif
|
|
|
|
#if defined(CONFIG_STM32_TIM20)
|
|
regval |= RCC_APB2ENR_TIM20EN;
|
|
#endif
|
|
|
|
#if defined(CONFIG_STM32_SAI1)
|
|
regval |= RCC_APB2ENR_SAI1EN;
|
|
#endif
|
|
|
|
#if defined(CONFIG_STM32_HRTIM1)
|
|
regval |= RCC_APB2ENR_HRTIM1EN;
|
|
#endif
|
|
|
|
putreg32(regval, STM32_RCC_APB2ENR);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_rcc_enablehse
|
|
*
|
|
* Description:
|
|
* Enable the High-Speed External (HSE) Oscillator.
|
|
*
|
|
****************************************************************************/
|
|
|
|
#if defined (USE_HSE)
|
|
static inline bool stm32_rcc_enablehse(void)
|
|
{
|
|
uint32_t regval;
|
|
uint32_t timeout;
|
|
|
|
/* Enable External High-Speed Clock (HSE) */
|
|
|
|
regval = getreg32(STM32_RCC_CR);
|
|
#if defined(STM32_HSEBYP_ENABLE) /* May be defined in board.h header file */
|
|
regval |= RCC_CR_HSEBYP; /* Enable HSE clock bypass */
|
|
#else
|
|
regval &= ~RCC_CR_HSEBYP; /* Disable HSE clock bypass */
|
|
#endif
|
|
regval |= RCC_CR_HSEON; /* Enable HSE */
|
|
putreg32(regval, STM32_RCC_CR);
|
|
|
|
/* Wait until the HSE is ready (or until a timeout elapsed) */
|
|
|
|
for (timeout = HSERDY_TIMEOUT; timeout > 0; timeout--)
|
|
{
|
|
if ((getreg32(STM32_RCC_CR) & RCC_CR_HSERDY) != 0)
|
|
{
|
|
/* HSE has been enabled successfully and is ready */
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/* HSE was not enabled successfully or timed out; this could
|
|
* mean that the external crystal or oscillator is missing or
|
|
* not working.
|
|
*/
|
|
|
|
return false;
|
|
}
|
|
#endif /* USE_HSE */
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_rcc_enablehsi
|
|
*
|
|
* Description:
|
|
* Enable the High-Speed Internal (HSI) Oscillator.
|
|
*
|
|
****************************************************************************/
|
|
|
|
#if defined (USE_HSI)
|
|
static inline bool stm32_rcc_enablehsi(void)
|
|
{
|
|
uint32_t regval;
|
|
uint32_t timeout;
|
|
|
|
/* Enable Internal High-Speed Clock (HSI) */
|
|
|
|
regval = getreg32(STM32_RCC_CR);
|
|
regval |= RCC_CR_HSION;
|
|
putreg32(regval, STM32_RCC_CR);
|
|
|
|
/* Wait until the HSI is ready (or until a timeout elapsed) */
|
|
|
|
for (timeout = HSIRDY_TIMEOUT; timeout > 0; timeout--)
|
|
{
|
|
if ((getreg32(STM32_RCC_CR) & RCC_CR_HSIRDY) != 0)
|
|
{
|
|
/* HSI has been enabled successfully and is ready */
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/* HSI was not enabled successfully or timed out */
|
|
|
|
return false;
|
|
}
|
|
#endif /* USE_HSI */
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_rcc_enablepll
|
|
*
|
|
* Description:
|
|
* Enable the Phase Locked Loop (PLL).
|
|
*
|
|
****************************************************************************/
|
|
|
|
#if defined (USE_PLL)
|
|
static inline bool stm32_rcc_enablepll(void)
|
|
{
|
|
uint32_t regval;
|
|
uint32_t timeout;
|
|
|
|
/* Preserve reserved bits when altering the PLLCFGR register */
|
|
|
|
regval = getreg32(STM32_RCC_PLLCFGR);
|
|
regval &= ~(RCC_PLLCFGR_RESERVED_MASK);
|
|
|
|
/* Configure PLL source and enables */
|
|
|
|
regval |= STM32_PLLCFGR_PLLSRC | STM32_PLLCFGR_PLLCFG;
|
|
|
|
/* Configure PLL multiplication and division factors */
|
|
|
|
regval |= STM32_PLLCFGR_PLLM | STM32_PLLCFGR_PLLN;
|
|
|
|
/* Configure PLL clock outputs division factors */
|
|
|
|
regval |= STM32_PLLCFGR_PLLP | STM32_PLLCFGR_PLLQ | STM32_PLLCFGR_PLLR;
|
|
|
|
/* Write PLLCFG register */
|
|
|
|
putreg32(regval, STM32_RCC_PLLCFGR);
|
|
|
|
/* Enable PLL */
|
|
|
|
regval = getreg32(STM32_RCC_CR);
|
|
regval |= RCC_CR_PLLON;
|
|
putreg32(regval, STM32_RCC_CR);
|
|
|
|
/* Wait until PLL ready (or timeout) */
|
|
|
|
for (timeout = PLLRDY_TIMEOUT; timeout > 0; timeout--)
|
|
{
|
|
if ((getreg32(STM32_RCC_CR) & RCC_CR_PLLRDY) != 0)
|
|
{
|
|
/* PLL has been enabled successfully and is ready */
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/* PLL was not enabled successfully or timed out */
|
|
|
|
return false;
|
|
}
|
|
#endif /* USE_PLL */
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_stdclockconfig
|
|
*
|
|
* Description:
|
|
* Called to change to new clock based on settings in board.h.
|
|
*
|
|
* Pre-conditions:
|
|
* rcc_reset() and rcc_resetbkp() have been called and the HSI is
|
|
* the MCU's SYSCLK.
|
|
****************************************************************************/
|
|
|
|
static void stm32_stdclockconfig(void)
|
|
{
|
|
uint32_t regval;
|
|
|
|
/* REVISIT:
|
|
*
|
|
* (1) We only support SYSCLK from HSE, HSI, or PLL, with PLL
|
|
* clocked by HSE or HSI. There is no configuration here for
|
|
* LSI, LSE, or HSI48.
|
|
*
|
|
* (2) We do not yet explicitly disable any clocks to save power.
|
|
*
|
|
* (3) Do we need to enable clock(s) to any bus(es) before we can
|
|
* access the PWR registers? And if so, do we need to disable
|
|
* any such clock(s) before programming the clock tree?
|
|
*
|
|
* (4) Do we need to enable write access or unlock anything
|
|
* before we can program any of the following things?
|
|
*/
|
|
|
|
/* Set up the power regulator per configured SYSCLK frequency.
|
|
*
|
|
* Before we begin, make sure voltage regulator is ready to receive
|
|
* any changes by waiting until VOSF bit is cleared by hardware.
|
|
*
|
|
* REVISIT: This should use the implementation in stm32_pwr.c, but
|
|
* it appears to be too different than this family and will need
|
|
* to be refactored accordingly. It is implemented here directly as
|
|
* a stopgap.
|
|
*/
|
|
|
|
/* REVISIT: Do we need to activate RCC_APB1ENR1_PWREN bit in
|
|
* RCC_APB1ENR1?
|
|
*/
|
|
|
|
while ((getreg32(STM32_PWR_SR2) & PWR_SR2_VOSF) != 0)
|
|
{
|
|
}
|
|
|
|
/* Choose the appropriate PWR VOS range and R1MODE based on the
|
|
* SYSCLK we're going to configure:
|
|
*
|
|
* R1MODE: Enable range 1 boost mode for 150MHz < SYSCLK <= 170MHz,
|
|
* disable range 1 boost mode for 26MHz < SYSCLK <= 150MHz.
|
|
*
|
|
* VOS: Range 1 for SYSCLK > 26MHz; range 2 for SYSCLK <= 26MHz.
|
|
*/
|
|
|
|
regval = getreg32(STM32_PWR_CR5);
|
|
regval &= ~(PWR_CR5_R1MODE);
|
|
regval |= PWR_CR5_R1MODE_SETTING;
|
|
putreg32(regval, STM32_PWR_CR5);
|
|
|
|
regval = getreg32(STM32_PWR_CR1);
|
|
regval &= ~(PWR_CR1_VOS_MASK);
|
|
regval |= PWR_CR1_VOS_RANGE_SETTING;
|
|
putreg32(regval, STM32_PWR_CR1);
|
|
|
|
/* Now we have to wait until VOSF bit is cleared by hardware
|
|
* again
|
|
*/
|
|
|
|
while ((getreg32(STM32_PWR_SR2) & PWR_SR2_VOSF) != 0)
|
|
{
|
|
}
|
|
|
|
/* Now we can program the clock tree */
|
|
|
|
#if defined(USE_HSE)
|
|
/* The HSE is being used, either as input to the PLL or as SYSCLK
|
|
* itself. Enable the HSE.
|
|
*/
|
|
|
|
if (stm32_rcc_enablehse() != true)
|
|
{
|
|
/* REVISIT: If we get here, timeout occurred waiting for HSE ready.
|
|
* We should have some sort of mechanism by which the application
|
|
* software can query whether the MCU has started up properly, so
|
|
* that it could possibly report an error or at least not attempt
|
|
* to work with wrong timing. Currently, as there is no mechanism
|
|
* in place to do that, we do not configure the clock any further.
|
|
*/
|
|
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
#if defined (USE_HSI)
|
|
/* The HSI is being used, either as input to the PLL or as SYSCLK
|
|
* itself. Enable the HSI.
|
|
*/
|
|
|
|
if (stm32_rcc_enablehsi() != true)
|
|
{
|
|
/* REVISIT: If we get here, timeout occurred waiting for HSI ready.
|
|
* We should have some sort of mechanism by which the application
|
|
* software can query whether the MCU has started up properly, so
|
|
* that it could possibly report an error or at least not attempt
|
|
* to work with wrong timing. Currently, as there is no mechanism
|
|
* in place to do that, we do not configure the clock any further.
|
|
*/
|
|
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
#if defined(USE_PLL)
|
|
|
|
if (stm32_rcc_enablepll() != true)
|
|
{
|
|
/* REVISIT: If we get here, timeout occurred waiting for HSI ready.
|
|
* We should have some sort of mechanism by which the application
|
|
* software can query whether the MCU has started up properly, so
|
|
* that it could possibly report an error or at least not attempt
|
|
* to work with wrong timing. Currently, as there is no mechanism
|
|
* in place to do that, we do not configure the clock any further.
|
|
*/
|
|
|
|
return;
|
|
}
|
|
|
|
#endif
|
|
|
|
/* Configure FLASH wait states per the SYSCLK frequency that is about
|
|
* to go into effect and enable prefetch to reduce latency due to
|
|
* these wait states (ART accelerator).
|
|
*
|
|
* REVISIT: Should we also enable I-Cache and D-Cache? Also, the
|
|
* reference manual suggests that we must read the ACR register to
|
|
* make sure the latency setting has taken effect. Are we doing that
|
|
* correctly?
|
|
*/
|
|
|
|
regval = getreg32(STM32_FLASH_ACR);
|
|
regval &= ~FLASH_ACR_LATENCY_MASK;
|
|
regval |= FLASH_ACR_LATENCY_SETTING;
|
|
regval |= FLASH_ACR_PRFTEN;
|
|
putreg32(regval, STM32_FLASH_ACR);
|
|
|
|
while ((getreg32(STM32_FLASH_ACR) & FLASH_ACR_LATENCY_MASK) !=
|
|
FLASH_ACR_LATENCY_SETTING)
|
|
{
|
|
}
|
|
|
|
/* Before selecting the SYSCLK source, set the HPRE, PPRE1, and PPRE2
|
|
* dividers.
|
|
*/
|
|
|
|
#if (STM32_SYSCLK_FREQUENCY > 150000000) && (STM32_RCC_CFGR_HPRE == RCC_CFGR_HPRE_SYSCLK)
|
|
|
|
/* If SYSCLK > 150MHz, temporarily set the HCLK prescaler (RCC_CFGR_HPRE)
|
|
* to divide by 2 (RCC_CFGR_HPRE_SYSCLKd2) before changing SYSCLK source
|
|
* to PLL. Afterwards, (after waiting at least 1us) change back to no
|
|
* division (RCC_CFGR_HPRE_SYSCLK). See reference manual, section 6.1.5.
|
|
*/
|
|
|
|
regval = getreg32(STM32_RCC_CFGR);
|
|
regval &= ~(RCC_CFGR_HPRE_MASK);
|
|
regval |= RCC_CFGR_HPRE_SYSCLKd2;
|
|
putreg32(regval, STM32_RCC_CFGR);
|
|
#endif
|
|
|
|
/* Select the system clock source as defined in board.h. This could
|
|
* be the HSI, HSE, or PLL (most likely the PLL).
|
|
*/
|
|
|
|
regval = getreg32(STM32_RCC_CFGR);
|
|
regval &= ~(RCC_CFGR_SW_MASK);
|
|
regval |= STM32_SYSCLK_SW;
|
|
putreg32(regval, STM32_RCC_CFGR);
|
|
|
|
/* Wait until the selected source is used as the system clock source */
|
|
|
|
while ((getreg32(STM32_RCC_CFGR) & RCC_CFGR_SWS_MASK) != STM32_SYSCLK_SWS)
|
|
{
|
|
}
|
|
|
|
/* Before we set HCLK prescaler to the correct value, temporarily
|
|
* divide APB1 and APB2 clocks by 16 to avoid problems.
|
|
*/
|
|
|
|
regval = getreg32(STM32_RCC_CFGR);
|
|
regval &= ~(RCC_CFGR_PPRE1_MASK | RCC_CFGR_PPRE2_MASK);
|
|
regval |= (RCC_CFGR_PPRE1_HCLKd16 | RCC_CFGR_PPRE2_HCLKd16);
|
|
putreg32(regval, STM32_RCC_CFGR);
|
|
|
|
/* Now set HCLK prescaler to the correct value */
|
|
|
|
regval = getreg32(STM32_RCC_CFGR);
|
|
regval &= ~(RCC_CFGR_HPRE_MASK);
|
|
regval |= STM32_RCC_CFGR_HPRE;
|
|
putreg32(regval, STM32_RCC_CFGR);
|
|
|
|
/* Now set APB1 and APB2 prescalers to the correct value */
|
|
|
|
regval = getreg32(STM32_RCC_CFGR);
|
|
regval &= ~(RCC_CFGR_PPRE1_MASK | RCC_CFGR_PPRE2_MASK);
|
|
regval |= (STM32_RCC_CFGR_PPRE1 | STM32_RCC_CFGR_PPRE2);
|
|
putreg32(regval, STM32_RCC_CFGR);
|
|
|
|
/* Configure FDCAN source clock */
|
|
|
|
#if defined(STM32_CCIPR_FDCANSRC)
|
|
regval = getreg32(STM32_RCC_CCIPR);
|
|
regval &= ~RCC_CCIPR_FDCANSEL_MASK;
|
|
regval |= STM32_CCIPR_FDCANSRC;
|
|
putreg32(regval, STM32_RCC_CCIPR);
|
|
#endif
|
|
|
|
#if defined(CONFIG_STM32_ADC1) || defined(CONFIG_STM32_ADC2)
|
|
/* Configure ADC12 clock */
|
|
|
|
regval = getreg32(STM32_RCC_CCIPR);
|
|
regval &= ~RCC_CCIPR_ADC12SEL_MASK;
|
|
regval |= RCC_CCIPR_ADC12SEL_PLLP;
|
|
putreg32(regval, STM32_RCC_CCIPR);
|
|
#endif
|
|
|
|
#if defined(CONFIG_STM32_ADC3) || defined(CONFIG_STM32_ADC4) || \
|
|
defined(CONFIG_STM32_ADC5)
|
|
/* Configure ADC345 clock */
|
|
|
|
regval = getreg32(STM32_RCC_CCIPR);
|
|
regval &= ~RCC_CCIPR_ADC345SEL_MASK;
|
|
regval |= RCC_CCIPR_ADC345SEL_PLLP;
|
|
putreg32(regval, STM32_RCC_CCIPR);
|
|
#endif
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: rcc_enableperipherals
|
|
*
|
|
* Description:
|
|
* Enable all peripheral buses and all configured peripherals.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static inline void rcc_enableperipherals(void)
|
|
{
|
|
rcc_enableahb1();
|
|
rcc_enableahb2();
|
|
rcc_enableahb3();
|
|
rcc_enableapb1();
|
|
rcc_enableapb2();
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Public Functions
|
|
****************************************************************************/
|
|
|