打印
[其他ST产品]

STM32的时钟配置

[复制链接]
321|12
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
5个时钟源
HSI,HSE,LSI,LSE,PLL

HSE为高速外部时钟,频率范围4~16 MHz

PLL的时钟源可以为:
HSE/2
HSE
HSI/2
倍频系数为2~16倍

STM32可以选择一个时钟信号输出到MCO脚,即PA8上,可以选择位PLL输出的二分频,HSI,HSE或系统时钟

注意:任何一个外设之前,都必须使能其对应的时钟

  • /**
  •   * @brief Reset and Clock Control
  •   */
  • typedef struct
  • {
  •   __IO uint32_t CR;
  •   __IO uint32_t CFGR;
  •   __IO uint32_t CIR;
  •   __IO uint32_t APB2RSTR;
  •   __IO uint32_t APB1RSTR;
  •   __IO uint32_t AHBENR;
  •   __IO uint32_t APB2ENR;
  •   __IO uint32_t APB1ENR;
  •   __IO uint32_t BDCR;
  •   __IO uint32_t CSR;
  • #ifdef STM32F10X_CL
  •   __IO uint32_t AHBRSTR;
  •   __IO uint32_t CFGR2;
  • #endif /* STM32F10X_CL */
  • #if defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || defined (STM32F10X_HD_VL)
  •   uint32_t RESERVED0;
  •   __IO uint32_t CFGR2;
  • #endif /* STM32F10X_LD_VL || STM32F10X_MD_VL || STM32F10X_HD_VL */
  • } RCC_TypeDef;

复制代码



使用特权

评论回复
沙发
两只袜子|  楼主 | 2022-12-27 14:19 | 只看该作者
如何查看SystemInit函数



可以看到这里有SystemInit函数的声明



打开这个文件,可以看到SystemInit函数的定义

  • /**
  •   * @brief  Setup the microcontroller system
  •   *         Initialize the Embedded Flash Interface, the PLL and update the
  •   *         SystemCoreClock variable.
  •   * @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) */
  •   /* Set HSION bit */
  •   RCC->CR |= (uint32_t)0x00000001;
  •   /* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
  • #ifndef STM32F10X_CL
  •   RCC->CFGR &= (uint32_t)0xF8FF0000;
  • #else
  •   RCC->CFGR &= (uint32_t)0xF0FF0000;
  • #endif /* STM32F10X_CL */
  •   /* Reset HSEON, CSSON and PLLON bits */
  •   RCC->CR &= (uint32_t)0xFEF6FFFF;
  •   /* Reset HSEBYP bit */
  •   RCC->CR &= (uint32_t)0xFFFBFFFF;
  •   /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */
  •   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 */
  •   /* Configure the Flash Latency cycles and enable prefetch buffer */
  •   SetSysClock();
  • #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
  • }

复制代码


如下图所示


使用特权

评论回复
板凳
两只袜子|  楼主 | 2022-12-27 14:21 | 只看该作者
函数解析
  • /* Reset the RCC clock configuration to the default reset state(for debug purpose) */
  •   /* Set HSION bit */
  •   RCC->CR |= (uint32_t)0x00000001;

复制代码



首先把CR寄存器的最低位置1

Set HSION Bit 相对于打开HSION,相对于把内部的8 MHz晶振打开



也就是这个



  • /* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
  • #ifndef STM32F10X_CL
  •   RCC->CFGR &= (uint32_t)0xF8FF0000;
  • #else
  •   RCC->CFGR &= (uint32_t)0xF0FF0000;
  • #endif /* STM32F10X_CL */

复制代码




以上代码主要是看你所用的芯片是大容量还是小容量,可以在魔术棒-C/C++里的宏处查看,例如,大容量为:

STM32F10X_HD

因此,这里相对于是根据所用的芯片容量选择RCC->CFGR寄存器的初始状态
  •   /* Reset HSEON, CSSON and PLLON bits */
  •   RCC->CR &= (uint32_t)0xFEF6FFFF;

复制代码




把HSEON,CSSON和PLLON对应的位清0
  •   /* Reset HSEBYP bit */
  •   RCC->CR &= (uint32_t)0xFFFBFFFF;

复制代码




把HSEBYP对应的位清0
  •   /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */
  •   RCC->CFGR &= (uint32_t)0xFF80FFFF;

复制代码




类似

使用特权

评论回复
地板
两只袜子|  楼主 | 2022-12-27 14:29 | 只看该作者
接下来是一个条件编译
  • #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 */

复制代码





执行的是这一段:



也就是关闭所有的中断,并清除所有的标志位

接下来调用了一个非常重要的函数
  •   /* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers */
  •   /* Configure the Flash Latency cycles and enable prefetch buffer */
  •   SetSysClock();

复制代码




使用特权

评论回复
5
两只袜子|  楼主 | 2022-12-27 14:34 | 只看该作者
看一下这个函数的实现:
  • /**
  •   * @brief  Configures the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers.
  •   * @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

复制代码




这个函数主要是看看这些标志符有没有被定义,这个定义我们是设置在下面这个文件中,我们进去看一下:

system_stm32f10x.c
  • #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

复制代码




SetSysClock函数通过判断宏定义标志符来判断要调用哪个函数

使用特权

评论回复
6
两只袜子|  楼主 | 2022-12-27 14:37 | 只看该作者
例如,我们在宏定义中定义了SYSCLK_FREQ_72MHz,那么SetSysClock函数就会调用SetSysClockTo72函数


SetSysClockTo72函数的实现
  • /**
  •   * @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
  •   */
  • static void SetSysClockTo72(void)
  • {
  •   __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
  •   /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/
  •   /* Enable HSE */
  •   RCC->CR |= ((uint32_t)RCC_CR_HSEON);
  •   /* 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)
  •   {
  •     /* Enable Prefetch Buffer */
  •     FLASH->ACR |= FLASH_ACR_PRFTBE;
  •     /* Flash 2 wait state */
  •     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 */
  •     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 */
  •     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 */
  •     RCC->CR |= RCC_CR_PLLON;
  •     /* Wait till PLL is ready */
  •     while((RCC->CR & RCC_CR_PLLRDY) == 0)
  •     {
  •     }
  •     /* Select PLL as system clock source */
  •     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 */
  •     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 */
  •   }
  • }

复制代码



使用特权

评论回复
7
两只袜子|  楼主 | 2022-12-27 14:38 | 只看该作者
首先,通过配置CR寄存器打开HSE,即外部高速时钟使能







使用特权

评论回复
8
两只袜子|  楼主 | 2022-12-27 14:40 | 只看该作者
接下来等待HSE的稳定,方法是查看CR寄存器的HSERDY位





若就绪,则HSEStatus = 1
接下来,当HSEStatus = 1时执行如下操作
  •   if (HSEStatus == (uint32_t)0x01)
  •   {
  •     /* Enable Prefetch Buffer */
  •     FLASH->ACR |= FLASH_ACR_PRFTBE;
  •     /* Flash 2 wait state */
  •     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 */
  •     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 */
  •     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 */
  •     RCC->CR |= RCC_CR_PLLON;
  •     /* Wait till PLL is ready */
  •     while((RCC->CR & RCC_CR_PLLRDY) == 0)
  •     {
  •     }
  •     /* Select PLL as system clock source */
  •     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 */
  •     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 */
  •   }

复制代码


使用特权

评论回复
9
两只袜子|  楼主 | 2022-12-27 14:41 | 只看该作者
由CPU的速度是远远快于FLASH的速度的,因此需要对FLASH控制器进行配置



通过CFGR寄存器设置AHB Prescale 设为1,泽恩HCLK就等于SYSCLK













使用特权

评论回复
10
两只袜子|  楼主 | 2022-12-27 14:43 | 只看该作者




本质上是将APB2的Prescale设置为1








使用特权

评论回复
11
两只袜子|  楼主 | 2022-12-27 14:43 | 只看该作者
经过以上配置:
HCLK = SYSCLK
PCLK2  = SYSCLK
PCLK1 = SYSCLK




此处条件编译

执行的是这段



  • CC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));
  •     RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_PREDIV1 | RCC_CFGR_PLLXTPRE_PREDIV1_Div2 | RCC_CFGR_PLLMULL6);

复制代码



使用特权

评论回复
12
两只袜子|  楼主 | 2022-12-27 14:44 | 只看该作者
将HSE作为时钟源,倍频系数为9,即将HSE直接作为时钟源,倍频9后的PLLCLK作为系统时钟,后面的预分频都是72 MHz









等待PLL就绪





PLL作为系统时钟,并等待其稳定


使用特权

评论回复
13
两只袜子|  楼主 | 2022-12-27 14:46 | 只看该作者
调用SystemInit函数的地方



startup_stm32f10x_hd.s
这里定义先执行SystemInit函数,再执行main函数



使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

2056

主题

7470

帖子

10

粉丝