STM32中级篇:RCC第二节——详解SetSysClockTo72系统时钟配置函数

目录

前言

STM32第九节(中级篇):RCC(第二节)——讲解系统时钟配置函数SetSysClockTo72

代码内容位置及检索

分析代码 

代码展示

时钟控制使能

闪存控制寄存器

配置AHP,APB1,APB2的总线时钟

配置锁相环时钟 

超频操作

小结


前言

        上节课我们讲了理论部分,那么我们这节课讲一下系统时钟配置函数SetSysClockTo72(固件库里面的系统时钟配置函数)。

        创作不易,点个关注吧!


STM32第九节(中级篇):RCC(第二节)——讲解系统时钟配置函数SetSysClockTo72

代码内容位置及检索

        首先我们拷贝一份之前固件库输出使得LED灯亮起的程序到一个新建的文件夹中,然后打开程序文件。找到其中的启动文件。在我们刚开始还没有stm32f10x.h文件时,我们曾写过一个函数但里面什么都没有,目的是为了骗过编译软件不报错。而这个函数就是 SystemInit 函数,那么他就是配置我们系统时钟的函数。

        我们右键点开该函数,发现该函数下有一个 SetSysClock(void)函数,我们打开该函数发现里面就是我们要使用的时钟类型,包括从24MHz到72MHz。        我们点开SYSCLK_FREQ定义,我们可以发现这里配置了宏定义。官方默认为72MHz,所以我们这里默认为72MHz输出。

分析代码 

代码展示

        紧接着我们就分析系统时钟配置函数SetSysClockTo72的具体代码:

        我们先看,#ifdef STM32F10X_CL这句代码写的是互联型的板子,而我们这里使用的是基础板,这里使用了条件编译的宏来区分代码。这里我们发现,我们不需要使用互联型的代码,那么我们可以对于这串代码进行瘦身并翻译注释:

/**
  * @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;

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

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

时钟控制使能

        我们从函数的开头来一步步分析代码的过程。首先定义函数static void SetSysClockTo72,然后下一行粗略控制总线时钟。 RCC->CR |= ((uint32_t)RCC_CR_HSEON)控制的是CR寄存器的HSEON 16位,该位置为1,16位启动完毕后17位也会置1,主要检测的是17位是否置为1来判断是否打开时钟:

        接着就是使用一个do——while循环来实现对于HSE的检测是否置1(如果HSEStatus的值为1,则跳出循环,为0则继续循环)然后判断(RCC->CR & RCC_CR_HSERDY) != RESET是否成立,对其进行赋值:

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;
  }  

        我们继续看正常的流程是什么样子的? 我们下一段代码有什么作用?我们的STM32程序是不是正常是在Flash里面,读取代码是需要等待的。

/* 如果HSE启动成功,程序则继续往下执行 */
  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;

闪存控制寄存器

        在这里所需要操作的就不是RCC的寄存器了,就是与Flash相关的寄存器。我们打开手册(闪存编程参考手册),我们找到位4:预取缓冲区使能,置1。

        然后我们观察手册可知,时延我们一般选010状态下的72MHz,完成我们的时延操作。

配置AHP,APB1,APB2的总线时钟


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

  

        这三行代码配置的是时钟配置寄存器中的4~13位 ,我们结合上节课的时钟树总图,我们就配置AHB为系统时钟72MHz,APB2为72MHz,APB1为36MHz:

配置锁相环时钟 

        配置好后,锁相环也有一个标志位 PLLRDY 25位。判断前一位是否为1。

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

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

    /* 等待准备 */
    while((RCC->CR & RCC_CR_PLLRDY) == 0)
    {
    }
    
    /* 选择pllclk为系统时钟 */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;    

    /* 等待切换 */
    while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
    {
    }

超频操作

        我们只需要配置锁相环RCC_CFGR_PLLMULL9为RCC_CFGR_PLLMULL16,这样我们就会得到一个超频时钟(128最高频率)。

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

小结

        到这里我们就写好了也分析了所有的代码,那么我们下节课学习使用HSE配置系统时钟并使用MCO输出监控系统时钟。

作者:Zhang-jk

物联沃分享整理
物联沃-IOTWORD物联网 » STM32中级篇:RCC第二节——详解SetSysClockTo72系统时钟配置函数

发表评论