[其他ST产品] STM32的时钟配置

[复制链接]
620|12
 楼主| 两只袜子 发表于 2022-12-27 14:16 | 显示全部楼层 |阅读模式
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;

复制代码


164328pop4dexqee2ot78d.png
 楼主| 两只袜子 发表于 2022-12-27 14:19 | 显示全部楼层
如何查看SystemInit函数

164328qdd65utt2bw8t7tt.png

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

164328xwwzr9ty6k8kts4s.png

打开这个文件,可以看到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
  • }

复制代码


如下图所示

164329iilyzaaityl5his8.png
 楼主| 两只袜子 发表于 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晶振打开

164330dcggeme1cgcgeekg.png

也就是这个

164331fa52izn5a5yc26c2.png

  • /* 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 */

复制代码


164331qjir7gpm7dtji351.png

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

STM32F10X_HD

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

复制代码


164331sw8be6h17mr838yg.png

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

复制代码


164331szr8eaadok8tzk1i.png

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

复制代码


164332qfxlejyx1445vxt4.png

类似
 楼主| 两只袜子 发表于 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 */

复制代码



164332oy70e7w05gefece4.png

执行的是这一段:

164333daxkud36e2gnehge.png

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

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

复制代码


164333yyfwc5slrclyn0ry.png

 楼主| 两只袜子 发表于 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

复制代码


164333hm76kacsk51m6pmo.png

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

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

复制代码


164334ewvw3w4un3ihurlr.png

SetSysClock函数通过判断宏定义标志符来判断要调用哪个函数
 楼主| 两只袜子 发表于 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 */
  •   }
  • }

复制代码


164334encotutmctucouu5.png
 楼主| 两只袜子 发表于 2022-12-27 14:38 | 显示全部楼层
首先,通过配置CR寄存器打开HSE,即外部高速时钟使能

164335jotpdiq0qq44qoxi.png

164336p32zqamyj2jcsvya.png


164336sw8x8j4088js098y.png
 楼主| 两只袜子 发表于 2022-12-27 14:40 | 显示全部楼层
接下来等待HSE的稳定,方法是查看CR寄存器的HSERDY位

164336hrprdwuyty6rn4dr.png

164337yhekn0ogou3g87ot.png

若就绪,则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 */
  •   }

复制代码


 楼主| 两只袜子 发表于 2022-12-27 14:41 | 显示全部楼层
由CPU的速度是远远快于FLASH的速度的,因此需要对FLASH控制器进行配置

164337j3wvskv3ktu3iw3u.png

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

164337xogk6b8sxwgj5831.png

164339vsruer9frb3r6bw9.png

164340v2rj263rhxh72yaj.png

164340nvp8loqmxxvp0qpl.png

164340awjwmjwpswcs8wc0.png


164341dzj0tpx07ou33xso.png
 楼主| 两只袜子 发表于 2022-12-27 14:43 | 显示全部楼层

164343kziifkaquuiuxilg.png


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

164342ej4flkjpp4pxsjft.png

164342rgxjsmsjzgo6p96j.png

164343xa9e5nd1zd85k5da.png

164344l6rzhx4oa6fxofbt.png
 楼主| 两只袜子 发表于 2022-12-27 14:43 | 显示全部楼层
经过以上配置:
HCLK = SYSCLK
PCLK2  = SYSCLK
PCLK1 = SYSCLK


164345wrpxrztrunvnvxt3.png

此处条件编译

执行的是这段

164345cbh9xxgchncdx6oq.png

  • 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);

复制代码



 楼主| 两只袜子 发表于 2022-12-27 14:44 | 显示全部楼层
将HSE作为时钟源,倍频系数为9,即将HSE直接作为时钟源,倍频9后的PLLCLK作为系统时钟,后面的预分频都是72 MHz

164345ofvbbfmphv5pbvzt.png

164346tz70fnnnavndpxw0.png

164346qvxwaxg70eivia3t.png

164346f6otn2st9ka92uhs.png

等待PLL就绪

164346aeyn77r7r7yrkne7.png

164347zb5zeyjfo2jjyeee.png

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

164348tvs2yb22yvlzv52v.png
 楼主| 两只袜子 发表于 2022-12-27 14:46 | 显示全部楼层
调用SystemInit函数的地方

164348f0nr1vuvydndxvru.png

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

164350q8bea7wecgvplxa8.png

您需要登录后才可以回帖 登录 | 注册

本版积分规则

2122

主题

8121

帖子

11

粉丝
快速回复 在线客服 返回列表 返回顶部