STM32时钟设置
2016-08-18 12:19
316 查看
MCU需要在时钟的驱动下才能正常工作,STM32F407 的工作主频最高能达到168MHz,而其外接晶振只有4-26MHz,需要通过内部的数字PLL电路进行配置,才能将内核时钟频率提升至168MHz,那具体需要怎样进行配置呢?其实,stm32的时钟配置相关的函数都在system_stm32f4xx.c这个文件中,这个c文件可以通过ST官方提供的一个xls文件自动生成,这里是对这个c文件做个详细介绍,知道了原理,便可以根据需要手动进行修改了。
首先看下如下图clock tree的PLL部分,系统时钟最大可以168MHz(PLL升频得来),这个需要对PLL进行配置,从下图可知,具体就是要设定P,Q,M,N这四个参数
由于PLLCLK = SourceCLK / M * N / P,这里SourceCLK代表的是PLL电路的输入时钟源,可以是高速外部时钟HSE,也可以是高速内部时钟HSI(STM32出厂自带的),假设是通过外接的8M晶振HSE作为PLL的输入时钟,显然可以通过168M
= 8M / 8 *336 / 2来得到168M的系统时钟,那么M=2,N=336,P=2,Q=7(USB之类的外设需要48M的时钟),于是便有了下面这样的宏定义:
首先看下如下图clock tree的PLL部分,系统时钟最大可以168MHz(PLL升频得来),这个需要对PLL进行配置,从下图可知,具体就是要设定P,Q,M,N这四个参数
由于PLLCLK = SourceCLK / M * N / P,这里SourceCLK代表的是PLL电路的输入时钟源,可以是高速外部时钟HSE,也可以是高速内部时钟HSI(STM32出厂自带的),假设是通过外接的8M晶振HSE作为PLL的输入时钟,显然可以通过168M
= 8M / 8 *336 / 2来得到168M的系统时钟,那么M=2,N=336,P=2,Q=7(USB之类的外设需要48M的时钟),于是便有了下面这样的宏定义:
/************************* PLL Parameters *************************************/ /* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N */ #define PLL_M 8 #define PLL_N 336 /* SYSCLK = PLL_VCO / PLL_P */ #define PLL_P 2 /* USB OTG FS, SDIO and RNG Clock = PLL_VCO / PLLQ */ #define PLL_Q 7有了这样的宏定义,便可以对相应的寄存器进行设置了,下面这个函数就是完成这个配置任务
/** * @brief Configures the System clock source, PLL Multiplier and Divider factors, * AHB/APBx prescalers and Flash settings * @Note This function should be called only once the RCC clock configuration * is reset to the default reset state (done in SystemInit() function). * @param None * @retval None */ static void SetSysClock(void) { /******************************************************************************/ /* PLL (clocked by HSE) used as System clock source */ /******************************************************************************/ __IO uint32_t StartUpCounter = 0, HSEStatus = 0; /* Enable HSE */ RCC->CR |= ((uint32_t)RCC_CR_HSEON);//必须先使能HSE,也就是外接的晶振 RCC_CR_HSEON = 0x0001 0000 /* Wait till HSE is ready and if Time out is reached exit */ do { HSEStatus = RCC->CR & RCC_CR_HSERDY; StartUpCounter++; } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT)); if ((RCC->CR & RCC_CR_HSERDY) != RESET) { HSEStatus = (uint32_t)0x01; } else { HSEStatus = (uint32_t)0x00; } if (HSEStatus == (uint32_t)0x01) { /* Select regulator voltage output Scale 1 mode, System frequency up to 168 MHz */ RCC->APB1ENR |= RCC_APB1ENR_PWREN; PWR->CR |= PWR_CR_VOS; /* HCLK = SYSCLK / 1*/ RCC->CFGR |= RCC_CFGR_HPRE_DIV1;//AHB时钟 /* PCLK2 = HCLK / 2*/ RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;//APB2时钟,84MHz max for STM32F407 /* PCLK1 = HCLK / 4*/ RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;//APB1时钟,42MHz max for STM32F407 /* Configure the main PLL */ RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) | (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);//PLL系数设置用的寄存器 /* Enable the main PLL */ RCC->CR |= RCC_CR_PLLON;//开启PLL /* Wait till the main PLL is ready */ while((RCC->CR & RCC_CR_PLLRDY) == 0) { } /* Configure Flash prefetch, Instruction cache, Data cache and wait state */ FLASH->ACR = FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS; /* Select the main PLL as system clock source */ RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW)); a0bf RCC->CFGR |= RCC_CFGR_SW_PLL; /* Wait till the main PLL is used as system clock source */ while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL); { } } else { /* If HSE fails to start-up, the application will have wrong clock configuration. User can add here some code to deal with this error */ } }上面这个函数被System_Init()函数引用,stm32上电进入到main函数之前,通过汇编写的启动文件调用System_Init()进行时钟初始化之后,也就是说在所有的c文件中,都不用再去调用System_Init(),系统便可以正常运行起来了。
void SystemInit(void) { /* FPU settings ------------------------------------------------------------*/ #if (__FPU_PRESENT == 1) && (__FPU_USED == 1) SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); /* set CP10 and CP11 Full Access */ #endif /* Reset the RCC clock configuration to the default reset state ------------*/ /* Set HSION bit */ RCC->CR |= (uint32_t)0x00000001;//首先需要用内部高速时钟作为系统主时钟 /* Reset CFGR register */ RCC->CFGR = 0x00000000; /* Reset HSEON, CSSON and PLLON bits */ RCC->CR &= (uint32_t)0xFEF6FFFF; /* Reset PLLCFGR register */ RCC->PLLCFGR = 0x24003010; /* Reset HSEBYP bit */ RCC->CR &= (uint32_t)0xFFFBFFFF; /* Disable all interrupts */ RCC->CIR = 0x00000000; #ifdef DATA_IN_ExtSRAM SystemInit_ExtMemCtl(); #endif /* DATA_IN_ExtSRAM */ /* Configure the System clock source, PLL Multiplier and Divider factors, AHB/APBx prescalers and Flash settings ----------------------------------*/ SetSysClock();//进行PLL配置 /* Configure the Vector Table location add offset address ------------------*/ #ifdef VECT_TAB_SRAM SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */ #else SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */ #endif }