【STM32】STM32 F4系列时钟树与RCC寄存器

  • STM32 5个时钟源

  • HSI(High Speed Internal)是高速内部时钟,RC振荡器,频率为16MHz,精度不高。可以直接作为系统时钟或者用作PLL时钟输入

  • HSE(High Speed External)是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为4MHz~26MHz,可借助PLL进行倍频。

  • LSI(Low Speed Internal)是低速内部时钟,RC振荡器,频率为32kHz,提供低功耗时钟。主要供独立看门狗和自动唤醒单元使用。

  • LSE(Low Speed External)是低速外部时钟,接频率为32.768kHz的石英晶体。这个主要是RTC时钟源。

  • PLL为锁相环倍频输出。

  1. 主 PLL(PLL)由 HSE 或者 HSI 提供时钟信号,并具有两个不同的输出时钟。 第一个输出 PLLP 用于生成高速的系统时钟(最高 168MHz) 第二个输出 PLLQ 用于生成 USB OTG FS 的时钟(48MHz),随机数发生器的时钟和 SDIO 时钟。
  1. 专用 PLL(PLLI2S)用于生成精确时钟,从而在 I2S 接口实现高品质音频性能。
  • STM32F4系列时钟树

  • 系统时钟SYSCLK来自三个时钟源

  1. HSI振荡器时钟
  1. HSE振荡器时钟
  1. PLL锁相环时钟
  • 各时钟作用

  1. 32kHz的LSI时钟可以供独立看门狗使用,
  1. 32kHz的LSI时钟和32.768kHz的LSE时钟都可以作为实时时钟外设RTC的时钟源;
  1. HSE时钟经2-31分频后也可以作为RTC时钟源;
  1. 系统时钟SYSCLK可以从HSI,HSE或者PLLCLK时钟三者之间选择,最高可以配置到168Mhz;
  1. 另外PLL48CK可以做用于生成 USB OTG FS 的时钟 (48 MHz)、随机数发生器的时钟 (≤48 MHz) 和 SDIO 时钟 (≤48 MHz);
  1. PLLI2SCLK时钟为用于生成精密时钟的专用PLL时钟,从而在 I2S 接口实现高品质音频性能;
  1. STM32F4 输出时钟 MCO1 和 MCO2。MCO1 是向芯片的 PA8 引脚输出时 钟。它有四个时钟来源分别为:HSI,LSE,HSE 和 PLL 时钟。MCO2 是向芯片的PC9 输出时钟,它同样有四个时钟来源分别为:HSE,PLL,SYSCLK 以及 PLLI2S 时钟。MCO 输出时钟频率最大不超过 100MHz。
  1. 以太网 PTP 时钟,AHB 时钟,APB2 高速时钟,APB1 低速时钟。 这些时钟都是来源于 SYSCLK 系统时钟。其中以太网 PTP 时钟是使用系统时钟。 AHB,APB2 和 APB1 时钟是经过 SYSCLK 时钟分频得来。这里大家记住,AHB 最大时钟为168MHz, APB2高速时钟最大频率为84MHz,而APB1低速时钟最大频 率为 42MHz。
  1. STM32F4 内部以太网 MAC 时钟的来源。对于 MII 接口来说,必须向外部 PHY 芯片提供 25Mhz 的时钟,这个时钟,可以由 PHY 芯片外接晶振,或者使用 STM32F4 的 MCO 输 出 来 提 供 。 然 后 , PHY 芯 片 再 给 STM32F4 提 供 ETH_MII_TX_CLK 和 ETH_MII_RX_CLK 时钟。对于 RMII 接口来说,外部必须 提供 50Mhz 的时钟驱动 PHY 和 STM32F4 的 ETH_RMII_REF_CLK,这个 50Mhz 时钟可以来自 PHY、有源晶振或者 STM32F4 的 MCO。
  1. 指外部 PHY 提供的 USB OTG HS(60MHZ)时钟。
  • 补充:

1)这里还需要说明一下,Cortex 系统定时器 Systick 的时钟源可以是 AHB 时钟 HCLK 或 HCLK 的 8 分频。具体配置请参考 Systick 定时器配置。 2)在以上的时钟输出中,有很多是带使能控制的,例如 AHB 总线时钟、内核时钟、各种 APB1 外设、APB2 外设等等。

  • 主PLL时钟第一个高速时钟输出PLLP的计算方法

从图可以看出主 PLL 时钟的时钟源要先经过一个分频系数为 M 的分频器,然后经过 倍频系数为 N 的倍频器出来之后的时候还需要经过一个分频系数为 P(第一个输出 PLLP)或 者 Q(第二个输出 PLLQ)的分频器分频之后,最后才生成最终的主 PLL 时钟。 例如我们的外部晶振选择 8MHz。同时我们设置相应的分频器 M=8,倍频器倍频系数 N=336, 分频器分频系数 P=2,那么主 PLL 生成的第一个输出高速时钟 PLLP 为:

PLL=8MHz * N/ (M*P)=8MHz* 336 /(8*2) = 168MHz

如果我们选择HSE为PLL时钟源,同时SYSCLK时钟源为PLL,那么SYSCLK时钟为 168MHz。

  • STM32F4时钟初始化配置

STM32F4 时钟系统初始化是在 system_stm32f4xx.c 中的 SystemInit()函数中完成的。对于系 统时钟关键寄存器设置主要是在 SystemInit 函数中调用 SetSysClock()函数来设置的。

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;

#if defined (DATA_IN_ExtSRAM) || defined (DATA_IN_ExtSDRAM)
  SystemInit_ExtMemCtl(); 
#endif /* DATA_IN_ExtSRAM || DATA_IN_ExtSDRAM */
         
  /* Configure the System clock source, PLL Multiplier and Divider factors, 
     AHB/APBx prescalers and Flash settings ----------------------------------*/
  SetSysClock();

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

SystemInit 函数开始先进行浮点运算单元设置,然后是复位 PLLCFGR,CFGR 寄存器,同时 通过设置 CR 寄存器的 HSI 时钟使能位来打开 HSI 时钟。默认情况下如果 CFGR 寄存器复位, 那么是选择 HSI 作为系统时钟,这点大家可以查看 RCC->CFGR 寄存器的位描述最低 2 位可以 得知,当低两位配置为 00 的时候(复位之后),会选择 HSI 振荡器为系统时钟。也就是说,调 用 SystemInit 函数之后,首先是选择 HSI 作为系统时钟。下面是 RCC->CFGR 寄存器的位 1:0 配置描述

  • SetSysClock 函数

static void SetSysClock(void)
{
     __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
     /*使能 HSE*/
     RCC->CR |= ((uint32_t)RCC_CR_HSEON);
     /* 等待 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)
     {
         /* Select regulator voltage output Scale 1 mode */
         RCC->APB1ENR |= RCC_APB1ENR_PWREN;
         PWR->CR |= PWR_CR_VOS;
         /* HCLK = SYSCLK / 1*/
         RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
         
         /* PCLK2 = HCLK / 2*/
         RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;
 
         /* PCLK1 = HCLK / 4*/
         RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;
         /* PCLK2 = HCLK / 2*/
         RCC->CFGR |= RCC_CFGR_PPRE2_DIV1;
         
         /* PCLK1 = HCLK / 4*/
         RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;
         /* Configure the main PLL */
         RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
         (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);
         /* 使能主 PLL*/
         RCC->CR |= RCC_CR_PLLON;
         /* 等待主 PLL 就绪 */
         while((RCC->CR & RCC_CR_PLLRDY) == 0)
         {
         }
         
         /* Configure Flash prefetch, Instruction cache, Data cache and wait state */
         FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN 
         FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;
         /* 设置主 PLL 时钟为系统时钟源 */
         RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
         RCC->CFGR |= RCC_CFGR_SW_PLL;
         /* 等待设置稳定(主 PLL 作为系统时钟源)*/
         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 */
 }
}

这段代码的大致流程是这样的:先使能外部时钟 HSE,等待 HSE 稳定之后,配置 AHB,APB1,APB2 时钟相关的分频因子,也就是相关外设的时钟。等待这些都配置完成之后, 打开主 PLL 时钟,然后设置主 PLL 作为系统时钟 SYSCLK 时钟源。如果 HSE 不能达到就绪状 态(比如外部晶振不能稳定或者没有外部晶振),那么依然会是 HSI 作为系统时钟。

RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |(RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);

这些参数是通过宏定义标识符的值来设置的。默认的配置在 System_stm32f4xx.c 文件开头的地 方配置。

#define PLL_M 8
#define PLL_Q 7
#define PLL_N 336
#define PLL_P 2

在开发过程中,我们可以通过调整这些值来设置我们的系统时钟。 这里还有个特别需要注意的地方,就是我们还要同步修改 stm32f4xx.h 中宏定义标识符 HSE_VALUE 的值为我们的外部时钟:

#if !defined (HSE_VALUE) 
#define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */
#endif /* HSE_VALUE */

这里默认固件库配置的是 25000000,我们外部时钟为 8MHz,所以我们根据我们硬件情况修改 为8000000 即可。

  • SystemInit()函数中设置的系统时钟大小:

SYSCLK(系统时钟) =168MHz
AHB 总线时钟(HCLK=SYSCLK) =168MHz
APB1 总线时钟(PCLK1=SYSCLK/4) =42MHz
APB2 总线时钟(PCLK2=SYSCLK/2) =84MHz
PLL 主时钟 =168MHz
  • STM32F4 时钟使能和配置

  • 外设时钟使能相关函数

void RCC_AHB1PeriphClockCmd(uint32_t RCC_AHB1Periph, FunctionalState NewState);
void RCC_AHB2PeriphClockCmd(uint32_t RCC_AHB2Periph, FunctionalState NewState);
void RCC_AHB3PeriphClockCmd(uint32_t RCC_AHB3Periph, FunctionalState NewState);
void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState);
void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);

这里主要有 5 个外设时钟使能函数。5 个函数分别用来使能 5 个总线下面挂载的外设时钟,这 些总线分别为:AHB1 总线,AHB2 总线,AHB3 总线,APB1 总线以及 APB2 总线。要使能某 个外设,调用对应的总线外设时钟使能函数即可。

  • 重要时钟源使能函数

void RCC_HSICmd(FunctionalState NewState);
void RCC_LSICmd(FunctionalState NewState);
void RCC_PLLCmd(FunctionalState NewState);
void RCC_PLLI2SCmd(FunctionalState NewState);
void RCC_PLLSAICmd(FunctionalState NewState);
void RCC_RTCCLKCmd(FunctionalState NewState);

  • 时钟功能函数

void RCC_LSEConfig(uint8_t RCC_LSE);
void RCC_SYSCLKConfig(uint32_t RCC_SYSCLKSource);
void RCC_HCLKConfig(uint32_t RCC_SYSCLK);
void RCC_PCLK1Config(uint32_t RCC_HCLK);
void RCC_PCLK2Config(uint32_t RCC_HCLK);
void RCC_RTCCLKConfig(uint32_t RCC_RTCCLKSource);
void RCC_PLLConfig(uint32_t RCC_PLLSource, uint32_t PLLM, uint32_t PLLN, uint32_t PLLP, uint32_t PLLQ);

  • 外设复位函数

void RCC_AHB1PeriphResetCmd(uint32_t RCC_AHB1Periph, FunctionalState NewState);
void RCC_AHB2PeriphResetCmd(uint32_t RCC_AHB2Periph, FunctionalState NewState);
void RCC_AHB3PeriphResetCmd(uint32_t RCC_AHB3Periph, FunctionalState NewState);
void RCC_APB1PeriphResetCmd(uint32_t RCC_APB1Periph, FunctionalState NewState);
void RCC_APB2PeriphResetCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);
  • RCC常用寄存器

  • RCC_CR

  • RCC_PLLCFGR

  • RCC_CFGR

  • RCC_AHB1ENR

此寄存器主要使能的是,USB OTG,以太网PTP,DMA,CCM,SRAM,CRC,GPIO口这些外设

  • RCC-AHB2ENR

此寄存器主要使能的是USB OTG时钟,硬件随机数发生器时钟,散列模块时钟,加密模块时钟,摄像头接口时钟这些时钟外设

  • RCC_AHB3ENR

此寄存器主要使能的是FSMC模块时钟。

  • RCC_APB1ENR

此寄存器主要使能的是DAC,PWR,CAN2,CAN1,I2C3,I2C2,I2C1,USART5,USART4,USART3,USART2,SPI3,SPI2,WWDG,TIM14,TIM13,TIM12,TIM7,TIM6,TIM5,TIM3,TIM2。这些外设

  • RCC_APB2ENR

此寄存器主要使能:TIME11,TIME10,TIME9,SYSCFG,SPI1,SDIO,ADC3,ADC2,ADC1,USART6,USART1,TIME8,TIME1。这些外设

总结:该文章为学习笔记,结合正点原子探索者的教程进行总结

  • 4
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,关于您的问题,首先需要了解一下stm32f4的时钟系统。stm32f4采用RCC(Reset and Clock Control)模块来生成各种时钟,并由该模块来控制系统时钟的源和分频器。 设置stm32f4的时钟分为以下几个步骤: 1. 开启RCC外设时钟 在使用RCC模块之前,需要开启RCC外设时钟。外设时钟开启方法如下所示: ``` //开启GPIOA和USART1外设时钟 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); ``` 2. 配置PLL时钟源和分频器 配置PLL的时钟源和分频器,可以通过RCC->PLLCFGR寄存器实现。其中,PLL时钟源可以选择外部晶振或者内部时钟源,分频器可以设置PLL输入时钟的分频系数,以及PLL输出时钟的分频系数。配置PLL的代码示例如下: ``` //配置PLL时钟源和分频系数 RCC_PLLConfig(RCC_PLLSource_HSE, 8, 336, 2, 7); ``` 3. 选择PLL作为系统时钟源 在将PLL配置好之后,还需要将其作为系统时钟源。可以通过RCC->CFGR寄存器实现。代码如下: ``` //选择PLL作为系统时钟源 RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); ``` 4. 配置AHB、APB1和APB2时钟分频器 最后,还需要配置AHB、APB1和APB2时钟分频器。可以通过RCC->CFGR寄存器实现。配置代码示例如下: ``` //配置AHB时钟分频系数 RCC_HCLKConfig(RCC_SYSCLK_Div1); //配置APB1时钟分频系数 RCC_PCLK1Config(RCC_HCLK_Div4); //配置APB2时钟分频系数 RCC_PCLK2Config(RCC_HCLK_Div2); ``` 以上就是关于如何设置stm32f4时钟的简单介绍。给您提供的信息是否有用?

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值