STM32F系列ARM Cortex_M3核微控制器基础之系统时钟三

网友投稿 1035 2022-09-30

STM32F系列ARM Cortex_M3核微控制器基础之系统时钟三

STM32F系列ARM Cortex_M3核微控制器基础之系统时钟三

STM32F系列ARM Cortex_M3核微控制器之系统时钟三

问题一:若未对系统进行时钟配置,那么系统上电后时钟系统将是怎样配置的?

在STM32启动文件startup_stm32f10x_hd.s中有下面一段汇编:

Reset_Handler PROC EXPORT Reset_Handler [WEAK] IMPORT __main IMPORT SystemInit LDR R0, =SystemInit BLX R0 LDR R0, =__main BX R0 ENDP

我们来看看system_stm32f10x.c文件中的SystemInit()函数对系统时钟的配置情况

/** * @brief Setup the microcontroller system * Initialize the Embedded Flash Interface, the PLL and update the * SystemCoreClock variable. 初始化内部Flash,PLL,更新系统时钟变量 * @note This function should be used only after reset. 仅能在复位后使用 * @param None * @retval None */void SystemInit (void){ /* Reset the RCC clock configuration to the default reset state(for debug purpose) */ //复位RCC时钟配置为默认复位状态(为了调试目的) /* Set HSION bit 置位内部高速时钟使能位*/ //内部8MHz振荡器开启 RCC->CR |= (uint32_t)0x00000001; /* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */ //复位系统时钟切换,AHB预分频,低速APB预分频,高速APB预分频,ADC预分频,微控制器时钟输出位 //HSI作为系统时钟,SYSCLK不分频作为HCLK,HCLK不分频做为PCLK1,PCLK2,PCLK2 2分频后作为ADC时钟,MCO引脚没有微控制器时钟输出#ifndef STM32F10X_CL RCC->CFGR &= (uint32_t)0xF8FF0000;#else RCC->CFGR &= (uint32_t)0xF0FF0000;#endif /* STM32F10X_CL */ /* Reset HSEON, CSSON and PLLON bits */ //复位外部高速时钟使能,时钟安全系统使能,PLL使能 //外部高速时钟关闭,时钟监测器关闭,PLL关闭 RCC->CR &= (uint32_t)0xFEF6FFFF; /* Reset HSEBYP bit */ //复位外部高速时钟旁路 //外部3-25MHz时钟没有旁路 RCC->CR &= (uint32_t)0xFFFBFFFF; /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */ //复位PLL输入时钟源,HSE分频作为PLL输入,PLL倍频系数,USB预分频位 //HSI振荡器时钟经2分频后作为PLL输入时钟,HSE不分频作为PLL输入时钟,PLL2倍频输出,PLL时钟1.5倍分频作为USB时钟 RCC->CFGR &= (uint32_t)0xFF80FFFF;#ifdef STM32F10X_CL /* Reset PLL2ON and PLL3ON bits */ RCC->CR &= (uint32_t)0xEBFFFFFF; /* Disable all interrupts and clear pending bits */ RCC->CIR = 0x00FF0000; /* Reset CFGR2 register */ RCC->CFGR2 = 0x00000000;#elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL) /* Disable all interrupts and clear pending bits */ RCC->CIR = 0x009F0000; /* Reset CFGR2 register */ RCC->CFGR2 = 0x00000000; #else /* Disable all interrupts and clear pending bits */ //失能所有时钟中断,清除挂起位 RCC->CIR = 0x009F0000;#endif /* STM32F10X_CL */ #if defined (STM32F10X_HD) || (defined STM32F10X_XL) || (defined STM32F10X_HD_VL) #ifdef DATA_IN_ExtSRAM SystemInit_ExtMemCtl(); #endif /* DATA_IN_ExtSRAM */#endif /* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers */ //配置系统时钟频率,HCLK,PCLK2,PCLK1预分频 /* Configure the Flash Latency cycles and enable prefetch buffer */ //配置Flash延时周期,使能预取缓存 SetSysClock();#ifdef VECT_TAB_SRAM SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */#else //向量表放置于内部FLASH SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */#endif }

该函数将RCC时钟先置为复位状态,然后调用SystemInit_ExtMemCtl()(如果定义了DATA_IN_ExtSRAM),调用SetSysClock()以及设置向量表的位置。这里不对SystemInit_ExtMemCtl()进行解释,置解释SetSysClock()函数

/** * @brief Configures the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers. 配置系统时钟频率,HCLK,PCLK2,PCLK1预分频 * @param None * @retval None */static void SetSysClock(void){#ifdef SYSCLK_FREQ_HSE SetSysClockToHSE();#elif defined SYSCLK_FREQ_24MHz SetSysClockTo24();#elif defined SYSCLK_FREQ_36MHz SetSysClockTo36();#elif defined SYSCLK_FREQ_48MHz SetSysClockTo48();#elif defined SYSCLK_FREQ_56MHz SetSysClockTo56(); #elif defined SYSCLK_FREQ_72MHz SetSysClockTo72();#endif /* If none of the define above is enabled, the HSI is used as System clock source (default after reset) */ //如果上面的宏定义都没定义,HSI用作系统时钟 }

这里定义了SYSCLK_FREQ_72MHz系统时钟频率

#if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)/* #define SYSCLK_FREQ_HSE HSE_VALUE */ #define SYSCLK_FREQ_24MHz 24000000#else/* #define SYSCLK_FREQ_HSE HSE_VALUE *//* #define SYSCLK_FREQ_24MHz 24000000 */ /* #define SYSCLK_FREQ_36MHz 36000000 *//* #define SYSCLK_FREQ_48MHz 48000000 *//* #define SYSCLK_FREQ_56MHz 56000000 */#define SYSCLK_FREQ_72MHz 72000000#endif

这里使能的函数是SetSysClockTo72();

/** * @brief Sets System clock frequency to 72MHz and configure HCLK, PCLK2 * and PCLK1 prescalers. 设置系统时钟为72MHz,配置HCLK,PCLK2,PCLK1预分频 * @note This function should be used only after reset. * @param None * @retval None */static void SetSysClockTo72(void){ __IO uint32_t StartUpCounter = 0, HSEStatus = 0; /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/ //配置SYSCLK, HCLK, PCLK2 and PCLK1 /* Enable HSE */ //使能高速外部振荡器 RCC->CR |= ((uint32_t)RCC_CR_HSEON); /* Wait till HSE is ready and if Time out is reached exit */ //等到HSE稳定,时间到则退出循环 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) { /* Enable Prefetch Buffer */ //使能预取缓冲 FLASH->ACR |= FLASH_ACR_PRFTBE; /* Flash 2 wait state */ //FLASH时序延迟2周期 FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY); FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2; /* HCLK = SYSCLK */ RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1; /* PCLK2 = HCLK */ RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1; /* PCLK1 = HCLK/2 */ RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;#ifdef STM32F10X_CL /* 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); RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 | RCC_CFGR_PLLMULL9); #else /* PLL configuration: PLLCLK = HSE * 9 = 72 MHz */ //PLL配置 HSE时钟作为PLL输入时钟 PLL9倍频 RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL)); RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);#endif /* STM32F10X_CL */ /* Enable PLL */ //使能PLL RCC->CR |= RCC_CR_PLLON; /* Wait till PLL is ready */ while((RCC->CR & RCC_CR_PLLRDY) == 0) { } /* Select PLL as system clock source */ //选择PLL作为系统时钟源 RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW)); RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL; /* Wait till PLL is used as system clock source */ //等到PLL作为系统时钟源 while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08) { } } 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 */ //如果HSE启动失败,应用会产生错误时钟配置,在这里对错误情况进行处理 }}

这里的配置是:HSE的外部晶振使用8MHz,HSE时钟作为PLL输入时钟,PLL 9倍频,SYSCLK = 72MHz,HCLK = AHB时钟为72MHz,PCLK1 = AHB/2 = 36MHz,PCLK2 = AHB = 72MHz。

初始化之后可以通过变量SystemCoreClock获取系统核心时钟频率(HCLK)。SystemCoreClock变量:包含核心时钟(HCLK),可以用于建立SysTick或配置其他参数

/******************************************************************************** Clock Definitions*******************************************************************************/#ifdef SYSCLK_FREQ_HSE uint32_t SystemCoreClock = SYSCLK_FREQ_HSE; /*!< System Clock Frequency (Core Clock) */#elif defined SYSCLK_FREQ_24MHz uint32_t SystemCoreClock = SYSCLK_FREQ_24MHz; /*!< System Clock Frequency (Core Clock) */#elif defined SYSCLK_FREQ_36MHz uint32_t SystemCoreClock = SYSCLK_FREQ_36MHz; /*!< System Clock Frequency (Core Clock) */#elif defined SYSCLK_FREQ_48MHz uint32_t SystemCoreClock = SYSCLK_FREQ_48MHz; /*!< System Clock Frequency (Core Clock) */#elif defined SYSCLK_FREQ_56MHz uint32_t SystemCoreClock = SYSCLK_FREQ_56MHz; /*!< System Clock Frequency (Core Clock) */#elif defined SYSCLK_FREQ_72MHz uint32_t SystemCoreClock = SYSCLK_FREQ_72MHz; /*!< System Clock Frequency (Core Clock) */#else /*!< HSI Selected as System Clock source */ uint32_t SystemCoreClock = HSI_VALUE; /*!< System Clock Frequency (Core Clock) */#endif

z再看看该文件下的另一个函数SystemCoreClockUpdate(),

由于SystemCoreClock变量中存储的是核心频率HCLK,每次系统时钟改变时,都需要使用该函数对该变量进行更新。

/** * @brief Update SystemCoreClock variable according to Clock Register Values. * The SystemCoreClock variable contains the core clock (HCLK), it can * be used by the user application to setup the SysTick timer or configure * other parameters. * 根据时钟寄存器值来更新SystemCoreClock变量,SystemCoreClock保存的是系统核心时钟(HCLK) * @note Each time the core clock (HCLK) changes, this function must be called * to update SystemCoreClock variable value. Otherwise, any configuration * based on this variable will be incorrect. * 当核心时钟变化时,必须调用该函数来更新SystemCoreClock变量。 * @note - The system frequency computed by this function is not the real * frequency in the chip. It is calculated based on the predefined * constant and the selected clock source: * 该函数计算的系统频率是基于预定义的频率和选择的时钟源,不一定是芯片真正的频率 * - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(*) * * - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(**) * * - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(**) * or HSI_VALUE(*) multiplied by the PLL factors. * * (*) HSI_VALUE is a constant defined in stm32f1xx.h file (default value * 8 MHz) but the real value may vary depending on the variations * in voltage and temperature. * * (**) HSE_VALUE is a constant defined in stm32f1xx.h file (default value * 8 MHz or 25 MHz, depedning on the product used), user has to ensure * that HSE_VALUE is same as the real frequency of the crystal used. * Otherwise, this function may have wrong result. * * - The result of this function could be not correct when using fractional * value for HSE crystal. * @param None * @retval None */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) || (defined STM32F10X_HD_VL) uint32_t prediv1factor = 0;#endif /* STM32F10X_LD_VL or STM32F10X_MD_VL or STM32F10X_HD_VL */ /* Get SYSCLK source -------------------------------------------------------*/ //得到SYSCLK所选时钟源 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 ----------------------*/ //得到PLL时钟源和倍频系数 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 */ //HSI 2分频后作为PLL时钟源 SystemCoreClock = (HSI_VALUE >> 1) * pllmull; } else { #if defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_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 */ //HSE时钟2分频 SystemCoreClock = (HSE_VALUE >> 1) * pllmull; } else { //HSE不分频 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; }

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Spring Boot之内嵌tomcat版本升级操作示例
下一篇:小程序如何获取经纬度信息实现定位功能(小程序如何获取经纬度信息实现定位功能的步骤)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~