STM32F2系列系统时钟默认配置

新到一家公司后,有个项目要用到STM32F207Vx单片机,找到网上的例子照猫画虎的写了几个例子,比如ADC,可是到了ADC多通道转换的时候就有点傻眼了,这里面的时钟跑的到底是多少M呢?单片机外挂的时钟是25M,由于该单片机时钟系统较为复杂,有内部高/低、外部高/低 、PLL锁相环时钟,又有AHB总线时钟、APB1/2时钟,而例子中很少讲到系统时钟的默认配置是怎么配置呢?那么就发点时间研究下这个单片机内部的复杂时钟系统吧。

下图是STM32F2系列的时钟树结构图:

1、内部高速时钟HSI、外部高速时钟HSE和PLL时钟PLLCLK时钟都接到了SW开关处,通过SW选择哪一路作为SYSCLK,SYSCLK经过AHB分频器进行分频得到HCLK,APB1和APB2是挂在总线AHB上的,通过APB1和APB2分频得出fpclk1和fpclk2。

2、PLL输入时钟源主要是靠外部高速时钟和内部高速时钟作为时钟源,通过PLLCFGR寄存器的bit22来选择具体哪一路作为时钟源。选择好了时钟源进入/M分频器,也就是PLLM进行分频,送入VCO,在通过xN,进行倍频,也就是PLLN:(1)通过/P进行分频(PLLP)得到PLLCLK;(2)通过/Q分频(PLLQ),得到PLL48CK。

然后边看代码边对照结构图进行分析,看软件如何给单片机配置系统时钟的。

然后找到启动代码“startup_stmf32xx.s”,该代码是用汇编写的,可以看到,在调用main函数之前,是先调用了SystemInit函数的,该函数是在“system_stm32f2xx.c”中

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

代码如下,变量直接赋个16进制的数,都不知道是啥意思,目的是干什么的,不知道,所以看下面代码时最好对照STM32F2x用户手册。当然这个只是一个初始化,待会主要看SetSysClock();这个函数,在调用该函数之前,我们知道单片机是先启用了内部高速时钟等一些配置。

void SystemInit(void)
{
  /* Reset the RCC clock configuration to the default reset state ------------*/
  /* Set HSION bit */
  RCC->CR |= (uint32_t)0x00000001; //RCC_CR复位值0x0000_xx83,内部高速时钟使能,也就是说上电开始就使用内部高速时钟,16MHZ

  /* Reset CFGR register */
  RCC->CFGR = 0x00000000;    //通过开关SW选择内部高速时钟作为系统时钟16MHZ
                                                        //AHB prescaler 不分频
                                                      //APB Low speed prescaler (APB1) 不分频,fplck1 = 16MHZ
                                                        //APB high-speed prescaler (APB2)不分频,fplck2 = 16MHZ
                              //MCO1和MCO2时钟输出等配置可参考用户手册Page95

  /* Reset HSEON, CSSON and PLLON bits */
  RCC->CR &= (uint32_t)0xFEF6FFFF;

  /* Reset PLLCFGR register */
  RCC->PLLCFGR = 0x24003010; //RCC_CFGR复位值是0x2400_3010

  /* Reset HSEBYP bit */
  RCC->CR &= (uint32_t)0xFFFBFFFF;  //对bit18 HSEBYP 设置为0,外部高速时钟被禁止

  /* 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();

  /* 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(void)函数中在配置完一些参数后,还调用了SetSysClock()函数,该函数代码如下

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);  //外部高速时钟使能,25MHZ

  /* Wait till HSE is ready and if Time out is reached exit */  //外部时钟使能后,得需要一点时间到达各个端口
  do
  {
    HSEStatus = RCC->CR & RCC_CR_HSERDY; //如果RCC_CR_HSERDY为0,说明外部时钟还没准备好,1说明外部时钟已准备好
    StartUpCounter++;//对读的次数进行累加,当累加次数到达1280次时,就意味着启动时间超时
  } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));

  if ((RCC->CR & RCC_CR_HSERDY) != RESET)//这里判断上面的do while循环是因哪个条件结束的
  {
    HSEStatus = (uint32_t)0x01;   //说明时钟已准备好了,才结束do whlie循环
  }
  else
  {
    HSEStatus = (uint32_t)0x00;  //说明是因为超时了而退出do while循环
  }

  if (HSEStatus == (uint32_t)0x01)
  {
    /* HCLK = SYSCLK / 1*/
    RCC->CFGR |= RCC_CFGR_HPRE_DIV1; //AHB不分频,AHB出来后时钟就是sysclk=120M

    /* PCLK2 = HCLK / 2*/
    RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;//APB2 2分频,fpclk2 = sysclk/2 = 60M

    /* PCLK1 = HCLK / 4*/
    RCC->CFGR |= RCC_CFGR_PPRE1_DIV4; //APB1 4分频,fplck1 = sysclk/4 = 30M

    /* Configure the main PLL */ //主要对PLL和PPI2S 进行配置
    RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
                   (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);
//配置完后RCC->PLLCFGR = 0x05403c19,然后对照寄存器RCC_PLLCFGR查看哪些位对应哪些功能
//通过bit5~bit0可计算出PLLM=25,那么input VCO = PLL input clock /PLLM = 25M/25 = 1M,对应时钟结构图中的/M
//通过bit14~bit6可计算出倍频因子PLLN = 240,那么VCO output clock = PLLN * input VCO = 240 * 1 = 240M,对应时钟结构图中的xN
//bit17~bit16可计算出分频因子PLLP = 2,那么PLLCLK = VCO output clock /PLLP = 240/2 = 120M
//bit22是选择给PLL输入的时钟源,输入时钟源有外部和内部高速时钟,这里选择的是外部高速时钟即PLL input clock = HSE =25M
//bit27~24可计算出分频因子PLLQ = 5,那么PLL48CK = VCO output clock/PLLQ = 240/5 = 48M

    /* Enable the main PLL */
    RCC->CR |= RCC_CR_PLLON; //使能PLL

    /* Wait till the main PLL is ready */
    while((RCC->CR & RCC_CR_PLLRDY) == 0)
    {
    }
        //到这里RCC->CR已配置完,最终值0x03036783
        //通过查看用户手册知道,内部高速时钟、外部高速时钟、PLL时钟都已开启

    /* Configure Flash prefetch, Instruction cache, Data cache and wait state */
    FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN | FLASH_ACR_DCEN | FLASH_ACR_LATENCY_3WS;

    /* Select the main PLL as system clock source */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    RCC->CFGR |= RCC_CFGR_SW_PLL;

        //到这里RCC->CFGR已配置完,最终值是0x0000_940A
        //通过查看用户手册,知道,PLL时钟作为系统时钟即120M
        //AHB不分频,即HCLK = 120M
        //APB1 4分频,即fpclk1 = 120/4=30M
        //APB2 2分频,即fpclk2 = 120/2=60M

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

}

OK,分析完这段代码后,调用系统固件函数后,现在知道了时钟树结构图中右边出来的时钟是多少MHz了吧。

时间: 2024-11-10 11:25:42

STM32F2系列系统时钟默认配置的相关文章

STM32F4xx那点事(二)——系统时钟的配置

每次接触一款新的单片机,我都会很好奇该单片机的系统时钟是多少MHz,怎样才能达到Datasheet中描述的最大系统时钟,该单片机的外设的时钟会是多少MHz呢?如果要使用延时,我怎么编写程序才能实现精准的延时呢?我认为这些问题是我开始接触新单片机之前需要了解的. 对于每款ARM Cortex-M系列单片机而言,厂商为了更好的推广自己的单片机,同时方便设计人员使用,降低产品开发周期,都会将该单片机的外设相关寄存器以及外设的相关函数都实现并打包,放在官方网站上免费供大家使用.STM32F405RG的标

CentOS和RedHat等系列系统 yum源配置、时间同步

一.yum源配置 1,进入yum源配置目录cd /etc/yum.repos.d 2,备份系统自带的yum源mv CentOS-Base.repo CentOS-Base.repo.bk下载163网易的yum源:wget http://mirrors.163.com/.help/CentOS6-Base-163.repo 3,更新玩yum源后,执行下边命令更新yum配置,使操作立即生效yum makecache yum list测试加缓存更新 4,除了网易之外,国内还有其他不错的yum源,比如中

关于debian,redhat系列系统的相关配置,和常见错误解决

一:Debian 1.  使用apt-get install  安装软件时有以下错误: W: GPG error: \  lable: NO_PUBKEY  40976EAF437D05B 解决:运行以下命令: apt-key adv --keyserver keyserver.ubuntu.com --recv-keys  40976EAF437D05B5 2.  或者出现的这样的问题: E: Sub-process /usr/bin/dpkg returned an error code (

STM32F4_RCC系统时钟配置及描述

Ⅰ.概述 对于系统时钟应该都知道它的作用,就是驱动整个芯片工作的心脏,如果没有了它,就等于人没有了心跳. 对于使用开发板学习的朋友来说,RCC系统时钟这一块知识估计没怎么去配置过,原因在于开发板提供的晶振基本上都是官方标准的时钟频率,使用官方的标准库,这样系统时钟就是默认的配置,也就是默认的频率.但对于自己设计开发板,或者想要改变系统时钟频率(如:降低功耗就需要降频)的朋友来说,配置系统时钟就有必要了. 关于时钟这一块对定时器(TIM.RTC.WDG等)相关的外设也比较重要,因为要求精准,就需要

认识STM32的系统时钟

STM32共有五个时钟源,分别是: HSI是高速内部时钟.RC振荡器,频率为8MHz: HSE是高速外部时钟,频率范围为4~6MHz; (可接石英/陶瓷谐振器或者接外部时钟源) LSI是低速内部时钟,频率40kHz; (独立看门狗时钟源.可作RTC时钟源) LSE是低速外部时钟,频率为32.768kHz石英晶体; (主要RTC时钟源) PLL是锁相环倍频输出,频率可选择为HSI/2.HSE或者HSE/2.倍频可选择2~16倍,但其输出频率最大不超过72MHz: 此处重点介绍系统时钟,一般其他所有

STM32F2系列时钟的配置

前一节详细介绍了系统默认的时钟配置,及各路时钟输出是多少,这是默认配置的,但实际使用的时钟默认的时钟并不符合要求,所以就得知道如何调用库函数进行配置. 最好的资料就是查阅stm32f2xx_rcc.c文件,里面有各种功能函数,并有详细的注释,这让我们这样的新手上手是非常快的. //VCO = PLL input clock(HSE or HSI)/PLLM //倍频电压后值V = VCO * PLLN //sysclk = V / PLLP //PLL48CK = V / PLLQ #defin

32系统时钟配置

 时钟是STM32单片机的驱动源,使用任何一个外设都必须打开相应的时钟.这样的好处就是,如果不使用一个外设的时候,就把它的时钟关掉,从而可以降低系统的功耗,达到节能,实现低功耗的效果.(低功耗) 在STM32中,有五个时钟源,为HSI.HSE.LSI.LSE.PLL. ①.HSI是高速内部时钟,RC振荡器,频率为8MHz. ②.HSE是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为4MHz~16MHz. ③.LSI是低速内部时钟,RC振荡器,频率为40kHz. ④.LSE是低速

Cotex-M3内核LPC17xx系列时钟及其配置方法

一.背景: 最近正在接手一个项目,核心芯片既是LPC17XX系列MCU,内核为ARM的Cotex-M3内核. 想要玩转一个MCU,就一定得搞定其时钟! 时钟对MCU而言,就好比人类的心脏.由其给AHB.APB总线供给血液(时钟频率),而挂在AHB(Advance High Bus)总线上的器件就像是我们的各个器官,挂在APB(Adance Peripheral Bus)总线的外设就像是人类的四肢.各个器官和四肢只有在你的血液(时钟频率)供给恰到好处时才能正常运转. 本篇文章既是对LPC17xx系

STM32F4系统时钟配置及描述

STM32F4系统时钟配置及描述 stm32f407时钟配置方法(感觉很好,分享一下)